This project investigates movement of GPS collard roe deer in the area of Trento, Italy. It compares recorded GPS data of five animals (Agostino, Alessandra, Daniela, Decimo, and Sandro) with simulated roe deer trajectories in order to assess to what extent roe deer movement can be explained by altitude and/or land use. The results from this project show that the roe deer stick to a relatively small home range and stable altitude compared to the simulated locations. Roe deer had a preference for forest and pasture. However, the difference with simulated data is small, which can be explained by the high prevalence of these land use types in the home range of the roe deer.
Prepare working environment
# check if libraries are installed
if (!require("dplyr")) install.packages("dplyr")
if (!require("sp")) install.packages("sp")
if (!require("sf")) install.packages("sf")
if (!require("DBI")) install.packages("DBI")
if (!require("RSQLite")) install.packages("RSQLite")
if (!require("raster")) install.packages("raster")
if (!require("adehabitatLT")) install.packages("adehabitatLT")
if (!require("lubridate")) install.packages("lubridate")
if (!require("ggplot2")) install.packages("ggplot2")
if (!require("gridExtra")) install.packages("gridExtra")
if (!require("leaflet")) install.packages("leaflet")
if (!require("rlist")) install.packages("rlist")
if (!require("rasterVis")) install.packages("rasterVis")
# load libraries
library(dplyr)
library(sp)
library(sf)
library(DBI)
library(raster)
library(adehabitatLT)
library(lubridate)
library(ggplot2)
library(gridExtra)
library(leaflet)
library(rlist)
library(rasterVis)
# import functions
source("R/retrieveData.R")
source("R/saveDataInDB.R")
source("R/simulateMovement.R")
source("R/createSpatialLine.R")
source("R/extractRasterValues.R")
source("R/plotProfiles.R")
source("R/combineSimTrack.R")
source("R/sumStats.R")
source("R/boxplotProfiles.R")
source("R/addLegend.R")
# project variables
# downloadlinks
movementDataURL = "extras.springer.com/2014/978-3-319-03742-4/trackingDB_datasets.zip"
environmentalURL = "https://drive.google.com/uc?export=download&id=1nb7q8TQGAkzTcGtSMS0Nig_DAhB2lClJ"
landUseLegendURL = "https://www.eea.europa.eu/data-and-maps/data/corine-land-cover-2006-raster-1/corine-land-cover-classes-and/clc_legend.csv/at_download/file"
# projections
proj4WGS84 <- "+proj=longlat +datum=WGS84 +no_defs"
proj4zone32 <- "+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs"
proj4Mercator <- "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"
Obtain data
# download movement data and unzip
folder = "data"
retrieveData(movementDataURL, folder, unzip = TRUE)
# download environmental data and unzip
retrieveData(environmentalURL, folder, unzip = TRUE)
# download legend for corine land cover (landUse)
retrieveData(landUseLegendURL, folder, filename = "landUseLegend.csv")
# Load environmental data to global environment
DEM <- raster(list.files(path = "data/GoogleEarthData", pattern = glob2rx('*DEM*.tif'), full.names = TRUE))
landsat <- brick(list.files(path = "data/GoogleEarthData", pattern = glob2rx('*Landsat*.tif'), full.names = TRUE))
landUse <- raster(list.files(path = "data/GoogleEarthData", pattern = glob2rx('*LandUse*.tif'), full.names = TRUE))
slope <- raster(list.files(path = "data/GoogleEarthData", pattern = glob2rx('*Slope*.tif'), full.names = TRUE))
landUseLegend <- read.csv(list.files(path = folder, pattern = glob2rx('*.csv'), full.names = TRUE))
Database management
We use an example dataset of roe deer movement from a book about spatial database management (Urbano and Cagnacci, 2014). The data are thus designed for use in a database and set up as interlinking datasets. Direct use in R is possible, but undesirable due to a lack of structure. Therefore, we set up an SQLite database in memory to process the data.
# create database connection
movementDB <- dbConnect(RSQLite::SQLite(), "")
# get files
gpsData <- list.files(path = "data/tracking_db/data/sensors_data/", pattern = glob2rx('GSM0*.csv'), full.names = TRUE)
sensorsAnimals <- list.files(path = "data/tracking_db/data/sensors_animals/", pattern = glob2rx('*.csv'), full.names = TRUE)
sensors <- list.files(path = "data/tracking_db/data/sensors/", pattern = glob2rx('*.csv'), full.names = TRUE)
animals <- list.files(path = "data/tracking_db/data/animals/", pattern = glob2rx('*.csv'), full.names = TRUE)
# specify column names for database tables
gpsDataColumnNames <- c("gpsSensorsCode","lineNo", "utcDate", "utcTime", "lmtDate", "lmtTime", "ecefX", "ecefY","ecefZ", "latitude", "longitude",
"height", "dop", "nav", "validated", "satsUsed", "ch01SatId", "ch01SatCnr", "ch02SatId", "ch02SatCnr", "ch03SatId", "ch03SatCnr", "ch04SatId", "ch04SatCnr", "ch05SatId", "ch05SatCnr", "ch06SatId", "ch06SatCnr", "ch07SatId", "ch07SatCnr", "ch08SatId", "ch08SatCnr", "ch09SatId", "ch09SatCnr", "ch10SatId", "ch10SatCnr", "ch11SatId", "ch11SatCnr", "ch12SatId", "ch12SatCnr", "mainVol", "buVol", "temp", "easting", "northing", "remarks")
sensorsAnimalsColumnNames <- c("animalsId","gpsSensorsId","startTime","EndTime","notes")
sensorsColumnNames <-c("gpsSensorsId", "gpsSensorsCode", "purchaseDate", "frequency", "vendor","model","sim")
animalsColumnNames <- c("animalsId", "animalsCode", "name","sex","ageClassCode", "speciesCode")
# save data in database
saveDataInDB(gpsData, movementDB, "gpsData", gpsDataColumnNames, TRUE)
saveDataInDB(sensorsAnimals, movementDB, "sensorsAnimals", sensorsAnimalsColumnNames, FALSE)
saveDataInDB(sensors, movementDB, "sensors", sensorsColumnNames, FALSE)
saveDataInDB(animals, movementDB, "animals", animalsColumnNames, FALSE)
The database can be queried with SQL. Since we want to link the GPS data with specific animals we need to join these tables. However, these tables do not have any common fields that can be used for a straightforward join. Embedding of SQL statements allows us to get to the required combination of data.
# query data from database
query <- '
SELECT
animals.name,
animals.sex,
dataWithAnimalId.utcDate, dataWithAnimalId.utcTime,
dataWithAnimalId.latitude, dataWithAnimalId.longitude,
dataWithAnimalId.height
FROM
(SELECT
dataWithSensorId.gpsSensorsCode,
dataWithSensorId.utcDate, dataWithSensorId.utcTime,
dataWithSensorId.latitude, dataWithSensorId.longitude,
dataWithSensorId.height,
dataWithSensorId.gpsSensorsId,
sensorsAnimals.animalsId
FROM
(SELECT
gpsData.gpsSensorsCode,
gpsData.utcDate, gpsData.utcTime,
gpsData.latitude, gpsData.longitude,
gpsData.height,
sensors.gpsSensorsId
FROM
gpsData
LEFT JOIN
sensors ON gpsData.gpsSensorsCode = sensors.gpsSensorsCode) AS dataWithSensorId
LEFT JOIN
sensorsAnimals ON dataWithSensorId.gpsSensorsId = sensorsAnimals.gpsSensorsId) AS dataWithAnimalId
LEFT JOIN
animals ON dataWithAnimalId.animalsId = animals.animalsId
;'
selectedMovementData <- dbGetQuery(movementDB, query)
Pre-processing
At this point we have the data we need. However, all data is stored as strings. The correct classes are assigned, before we can create a geometry out of the latitude and longitude columns. We choose the WGS84 zone 32 (EPSG:32632) as coordinate system as it provides enough detail for our analyses.
# correct classes
selectedMovementData$sex <- factor(selectedMovementData$sex)
class(selectedMovementData$latitude) <- "numeric"
class(selectedMovementData$longitude) <- "numeric"
class(selectedMovementData$height) <- "numeric"
selectedMovementData$date <- dmy_hms(paste(selectedMovementData$utcDate, selectedMovementData$utcTime), tz = "UTC")
# remove redundant columns
selectedMovementData[3:4] <- list(NULL)
# remove rows with NA for location
selectedMovementDataNoNA <- selectedMovementData[!is.na(selectedMovementData$latitude) | !is.na(selectedMovementData$longitude),]
# create spatial data frame projected in WGS84 zone 32
coords <- selectedMovementDataNoNA[,c(4:3)]
WGS84movementSDF <- SpatialPointsDataFrame(coords = coords, data = selectedMovementDataNoNA, proj4string = CRS(proj4WGS84))
movementSDF <- spTransform(WGS84movementSDF, CRS(proj4zone32))
# create trajectories
movementTrajectories <- as.ltraj(xy = coordinates(movementSDF), date = movementSDF$date, id = movementSDF$name)
# and create a dataframe to group our data and add height information
dataframeTrajectories <- ld(movementTrajectories)
groups <- dataframeTrajectories %>% mutate(height = movementSDF$height) %>% group_by(id)
trajectories <- dl(groups)
We are curious where “our” roe deer are going! For visualization purposes we need to create spatial lines of the GPS recorded trajectories.
# select distinct animals
animalNames <- distinct(groups, id)[[1]]
for (animal in animalNames){
# get location data from nth animal
locationdatainit <- groups[(groups$id == animal),]
# create spatial line
assign(paste0("trajectinit",animal), createSpatialLine(locationdata = locationdatainit, proj4dataframe = proj4zone32, proj4line = proj4WGS84, lineId = animal))
}
An interactive leaflet map allows us to explore the GPS recorded movement of our roe deer, Agostino, Alessandra, Daniela, Decimo, and Sandro.
m <- leaflet() %>%
setView(lng=11.0367, lat=46.0331, zoom = 11) %>%
# baselayers
addTiles(group = 'Street map') %>%
addProviderTiles('Stamen.Terrain', group = 'Terrain') %>%
addProviderTiles('Esri.WorldImagery', group = 'Satellite') %>%
# overlay groups
addPolylines(data = trajectinitAgostino, weight = 1, opacity = 0.8, color = "red", group = 'Agostino') %>%
addPolylines(data = trajectinitAlessandra, weight = 1, opacity = 0.8, color = "blue", group = 'Alessandra') %>%
addPolylines(data = trajectinitDaniela, weight = 1, opacity = 0.8, color = "orange", group = 'Daniela') %>%
addPolylines(data = trajectinitDecimo, weight = 1, opacity = 0.8, color = "yellow", group = 'Decimo') %>%
addPolylines(data = trajectinitSandro, weight = 1, opacity = 0.8, color = "purple", group = 'Sandro') %>%
addLayersControl(
baseGroups = c('Street map', 'Terrain', 'Satellite'),
overlayGroups = c('Agostino', 'Alessandra', 'Daniela', 'Decimo', 'Sandro'),
options = layersControlOptions(collapsed = FALSE)
)
m
Oops! The data clearly contain some outliers. These need to be removed in order to perform reliable analyses. But how do we define which points are outliers? We look at boxplots of different variables in order to determine a suitable method to identify outliers.
# plot
p1 <- ggplot(groups, aes(x=id, y=x, fill = id)) + geom_boxplot(alpha=0.2) + theme(legend.position = "none") + ggtitle("x-coordinates of locations")
p2 <- ggplot(groups, aes(x=id, y=y, fill = id)) + geom_boxplot(alpha=0.2) + theme(legend.position = "none") + ggtitle("y-coordinates of locations")
p3 <- ggplot(groups, aes(x=id, y=dist, fill = id)) + geom_boxplot(alpha=0.2) + theme(legend.position = "none") + ggtitle("Distance between relocations")
p4 <- ggplot(groups, aes(x=id, y=abs.angle, fill = id)) + geom_boxplot(alpha=0.2) + theme(legend.position = "none") + ggtitle("Absolute angle between relocations")
p5 <- ggplot(groups, aes(x=id, y=rel.angle, fill = id)) + geom_boxplot(alpha=0.2) + theme(legend.position = "none") + ggtitle("Relative angle between relocations")
p6 <- ggplot(groups, aes(x=id, y=dt, fill = id)) + geom_boxplot(alpha=0.2) + theme(legend.position = "none") + ggtitle("Time between relocations")
grid.arrange(p1,p2,p3,p4,p5,p6, layout_matrix = rbind(c(1,2),c(3,4),c(5,6)))

These boxplots show the outliers very clearly in the x and y-coordinates as well as the distance and time between relocations. In previous steps we removed some measurements with NA’s for latitude and longitude to be able to convert the dataframe to a spatial dataframe. As a result, the time between relocations is not 100% accurate. We will therefore use only x-coordinates, y-coordinates and distance between relations to clean our dataset. Tresholds for the x and y-coordinates are based purely on these boxplots. To determine the treshold for the distance we take a look at the distribution of steplengths.
# plot histograms of distance between location points
par(mfrow=c(3, 2))
for (i in 1:length(id(movementTrajectories))){
hist(movementTrajectories[[i]]$dist, xlim = c(0, 5000), ylim = c(0, 1500), breaks = seq(0, 1000000, by = 100), xlab = "distance (m)", main = paste("Distance between relocations by", id(movementTrajectories)[i]))
}

Looking at the distribution of steplengths and taking into account the consideration that roe deer generally do not travel great distances, a moved distance of 1500m or higher in one relocation is considered unrealistic.
# tresholds
xMin <- 650000
xMax <- 700000
yMin <- 5092500
yMax <- 5107500
distMax <- 1500
# remove outliers based on x-coordinates and distance between relocations
groupsCleaned <- groups %>% filter(x < xMax) %>% filter(x > xMin) %>% filter(y < yMax) %>% filter(y > yMin) %>% filter(dist < distMax)
# cast back to ltraj
movementTrajectoriesCleaned <- dl(groupsCleaned)
For visualization purposes we create Spatial Lines of the recorded trajectories without outliers.
# select distinct animals
animalNames <- distinct(groupsCleaned, id)[[1]]
for (animal in animalNames){
# get location data from nth animal
locationdata <- groupsCleaned[(groupsCleaned$id == animal),]
# create spatial line
assign(paste0("traject",animal), createSpatialLine(locationdata = locationdata, proj4dataframe = proj4zone32, proj4line = proj4WGS84, lineId = animal))
}
We can now visualize the cleaned movement patterns of our beloved roe deer!
m <- leaflet() %>%
setView(lng=11.0367, lat=46.0331, zoom = 11) %>%
# baselayers
addTiles(group = 'Street map') %>%
addProviderTiles('Stamen.Terrain', group = 'Terrain') %>%
addProviderTiles('Esri.WorldImagery', group = 'Satellite') %>%
# overlay groups
addPolylines(data = trajectAgostino, weight = 1, opacity = 0.8, color = "red", group = 'Agostino') %>%
addPolylines(data = trajectAlessandra, weight = 1, opacity = 0.8, color = "blue", group = 'Alessandra') %>%
addPolylines(data = trajectDaniela, weight = 1, opacity = 0.8, color = "orange", group = 'Daniela') %>%
addPolylines(data = trajectDecimo, weight = 1, opacity = 0.8, color = "yellow", group = 'Decimo') %>%
addPolylines(data = trajectSandro, weight = 1, opacity = 0.8, color = "purple", group = 'Sandro') %>%
addLayersControl(
baseGroups = c('Street map', 'Terrain', 'Satellite'),
overlayGroups = c('Agostino', 'Alessandra', 'Daniela', 'Decimo', 'Sandro'),
options = layersControlOptions(collapsed = FALSE)
)
m
Note! The data might still contain a few wrongly recorded points (we are not sure whether Agostino really visited his aunt in Stravino for a coffee). However, we are not justified to remove these potential outliers on the basis of our previously defined cut-off point.
Boxplots allow for further assessment of the cleaned data. Looks a lot better, doesn’t it?
# boxplots
p1 <- ggplot(groupsCleaned, aes(x=id, y=x, fill = id)) + geom_boxplot(alpha=0.2) + theme(legend.position = "none") + ggtitle("x-coordinates of locations")
p2 <- ggplot(groupsCleaned, aes(x=id, y=y, fill = id)) + geom_boxplot(alpha=0.2) + theme(legend.position = "none") + ggtitle("y-coordinates of locations")
p3 <- ggplot(groupsCleaned, aes(x=id, y=dist, fill = id)) + geom_boxplot(alpha=0.2) + theme(legend.position = "none") + ggtitle("Distance between relocations")
p4 <- ggplot(groupsCleaned, aes(x=id, y=abs.angle, fill = id)) + geom_boxplot(alpha=0.2) + theme(legend.position = "none") + ggtitle("Absolute angle between relocations")
p5 <- ggplot(groupsCleaned, aes(x=id, y=rel.angle, fill = id)) + geom_boxplot(alpha=0.2) + theme(legend.position = "none") + ggtitle("Relative angle between relocations")
p6 <- ggplot(groupsCleaned, aes(x=id, y=dt, fill = id)) + geom_boxplot(alpha=0.2) + theme(legend.position = "none") + ggtitle("Time between relocations")
grid.arrange(p1,p2,p3,p4,p5,p6, layout_matrix = rbind(c(1,2),c(3,4),c(5,6)))

Data validation
The data is ready for the analyses!
Before we start our movement analysis, we will assess the reliability of our data. The altitude measurement of the GPS data needs to be validated through a comparison with the DEM. GPS data are not reliable if its mean altitude differs significantly from the DEM values at corresponding spatial points.
A boxplot allows us to have a first look at the difference in height measurement between DEM and GPS.
# calculate DEM height values at point locations for which GPS height data is available.
heightDEM <- extract(DEM, as.data.frame(groupsCleaned[,c("x","y")]), method='simple', na.rm=TRUE, df=TRUE)
heightDEM$animal <- unlist(groupsCleaned[,"id"])
colnames(heightDEM) <- c("ID", "rasterVal", "animal")
heightData <- data.frame(group = rep(c("DEM", "GPS"), each = nrow(heightDEM)), height = c(heightDEM$rasterVal, groupsCleaned$height))
# visualize
boxplot(height ~ group, heightData, main = "Height boxplot GPS and DEM", ylab = "Height")

Ooh no! The GPS data contains large outliers (the alps are not even 20 000m high!). Did Allessandro also have a coffee in outer space?
A paired t-test is performed to assess the reliability the measurements.
# perform a paired t-test to compare mean GPS and DEM height
tTest <- t.test(heightDEM$rasterVal, groupsCleaned$height, paired = TRUE, alternative = "two.sided")
print("Results of the paired t-test:")
[1] "Results of the paired t-test:"
tTest
Paired t-test
data: heightDEM$rasterVal and groupsCleaned$height
t = -9.7866, df = 10973, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-49.59823 -33.04543
sample estimates:
mean of the differences
-41.32183
The paired t-test confirms that there is a significant difference (p-value < 2.2e-16) in mean altitude between the GPS height measurement and the DEM height values. The mean difference between the two measurements amounts to 41 meters. This confirms our suspicion that the GPS altitude measurements are not always reliable. Therefore, we will use DEM altitude measurement for our further analysis.
Now that we have obtained reliable altitude measurements, we will extract landuse values for the recorded trajectories.
# extract landuse values of recorded trajectories
landuseTracks <- extract(landUse, as.data.frame(groupsCleaned[,c("x","y")]), method='simple', na.rm=TRUE, df=TRUE)
landuseTracks$animal <- unlist(groupsCleaned[,"id"])
colnames(landuseTracks) <- c("ID", "rasterVal", "animal")
Simulations
In the next section we will start with the simulations of animal trajectories. We will use the simm.crw function of the adehabitatLT package for the simulations. We wrapped this function in the simulateMovement function so that it is easy to specify the number of simulations and save all simulation in an convenient dataformat. The simulations start at the same location as the respective animal, and will have the same length.
# number of simulations per animal
nSimulations <- 5
# perform simulations
simulations <- simulateMovement(trajectories = movementTrajectoriesCleaned, nSimulations = nSimulations, proj4 = proj4zone32)
Let’s visualize some simulations on an interactive map!
# plot example of simulated trajectory
exampleSim1 <- simulations[[2]][[1]][[1]]
exampleSim2 <- simulations[[2]][[2]][[1]]
# create spatial line
simExample1WGS84 <- createSpatialLine(locationdata = exampleSim1, proj4dataframe = proj4zone32, proj4line = proj4WGS84, lineId = animal)
simExample2WGS84 <- createSpatialLine(locationdata = exampleSim2, proj4dataframe = proj4zone32, proj4line = proj4WGS84, lineId = animal)
m <- leaflet() %>%
setView(lng=11.0367, lat=46.0331, zoom = 11) %>%
# baselayers
addTiles(group = 'Street map') %>%
addProviderTiles('Stamen.Terrain', group = 'Terrain') %>%
addProviderTiles('Esri.WorldImagery', group = 'Satellite') %>%
# overlay groups
addPolylines(data = simExample1WGS84, weight = 1, opacity = 0.8, color = "orange", group = 'Simulation 1') %>%
addPolylines(data = simExample2WGS84 , weight = 1, opacity = 0.8, color = "red", group = 'Simulation 2') %>%
addPolylines(data = trajectAlessandra, weight = 1, opacity = 0.8, color = "blue", group = 'Alessandra') %>%
addLayersControl(
baseGroups = c('Street map', 'Terrain', 'Satellite'),
overlayGroups = c('Alessandra', 'Simulation 1', 'Simulation 2'),
options = layersControlOptions(collapsed = FALSE)
)
m
We extract the altitude and landuse values of simulated trajectories and store them in a matrix in order to compare them with the recorded GPS trajectories of our animals.
# extract altitude and landuse values of simulations
simulationElevations <- extractRasterValues(DEM, simulations)
simulationLandUse <- extractRasterValues(landUse, simulations)
# combine recorded and simulated height data in one matrix
simElCombi <- combineSimTrack(heightDEM, animalNames, simulationElevations)
simLandCombi <- combineSimTrack(landuseTracks, animalNames, simulationLandUse)
Comparison recorded and simulated trajectories
Elevation
We can explore whether our roe deer have a preference for altitude through a visualization of movement on a DEM.
# variables
colors <- c("red","blue", "orange", "yellow", "purple")
names <- list(c("Agostino", "Allessandra", "Daiela", " Decimo", "Sandro"))
# select theme to plot with right colors
myTheme=rasterTheme(region=rev(brewer.pal('YlGn', n=9)))
# create plot of DEM with added trajectories
levelplot(DEM, main = "Altitude of recorded roe deer locations", margin = FALSE, par.settings=myTheme, xlim = c(647000, 670000), key = list(space = 'bottom', points = list(lty = 1, col = colors), text = names )) +
latticeExtra::layer({
trajectAgostinoZone32 <- spTransform(trajectAgostino, CRS(proj4zone32))
sp.lines(trajectAgostinoZone32, col = 'red')}) +
latticeExtra::layer({
trajectAllessandraZone32 <- spTransform(trajectAlessandra, CRS(proj4zone32))
sp.lines(trajectAllessandraZone32, col = 'blue')}) +
latticeExtra::layer({
trajectDanielaZone32 <- spTransform(trajectDaniela, CRS(proj4zone32))
sp.lines(trajectDanielaZone32, col = 'orange')}) +
latticeExtra::layer({
trajectDecimoZone32 <- spTransform(trajectDecimo, CRS(proj4zone32))
sp.lines(trajectDecimoZone32, col = 'yellow')}) +
latticeExtra::layer({
trajectSandroZone32 <- spTransform(trajectSandro, CRS(proj4zone32))
sp.lines(trajectSandroZone32, col = 'purple')})

Plots allow us to compare the recorded altitude of our animals with the simulations.
# plot the profiles of the simulated profiles and the trajectory
plotProfiles(simElCombi, animalNames)





The recorded trajectories show clearly less variation than the simulated trajectories. This result suggest that roe deer like to stay on a similar altitude for a longer timeperiod.
In these boxplots we can compare the distribution of the elevation of the recorded trajectories and the simulated trajectories to confirm our visual interpretation of the plotted profiles.
# variables for boxplot
xlab <- "Trajectory"
ylab <- "Elevation (m)"
title <- "Comparison of recorded and simulated GPS trajectories of"
# visualize the difference between recorded and simulated data in boxplots
boxplotlist <- boxplotProfiles(simElCombi, animalNames, xlab, ylab, title, addName = TRUE)
# arrage boxplots
grid.arrange(boxplotlist[[1]],boxplotlist[[2]],boxplotlist[[3]],boxplotlist[[4]],boxplotlist[[5]], layout_matrix = rbind(c(1,2), c(3,4),c(5,6)))

We can also compare the summary statistics (mean and standard deviation) of the recorded and simulated trajectories.
# calculate summary statistics for the recorded and simulated trajectories
summaryStats <- sumStats(simElCombi, animalNames)
# create empty vectors
xAxSim <- as.integer()
meansRec <- as.numeric()
meansSim <- as.numeric()
sdRec <- as.numeric()
sdSim <- as.numeric()
# store the summary statistics in a vector for plotting
for (animal in 1:length(animalNames)){
meansRec <- c(meansRec, summaryStats[[animal]][1,1])
meansSim <- c(meansSim, summaryStats[[animal]][1,2:ncol(summaryStats[[animal]])])
sdRec <- c(sdRec, summaryStats[[animal]][3,1])
sdSim <- c(sdSim, summaryStats[[animal]][3,2:ncol(summaryStats[[animal]])])
# create an index vector for the x-axis
for (col in 1:length(2:ncol(summaryStats[[animal]]))){
xAxSim <- c(xAxSim, animal)
}
}
# plot
par(mfrow=c(1,2), xpd = TRUE)
plot(xAxSim, meansSim, col = c('grey'), ylim = c(400,1600), main = 'Mean elevation', xlab = 'animal number', ylab = 'elevation (m)', pch = 19)
points(meansRec, col = 'red', pch = 19)
plot(xAxSim, sdSim, col = c('grey'), ylim = c(100,650), main = 'Standard deviation elevation', xlab = 'animal number', ylab = 'elevation (m)', pch = 19)
points(sdRec, col = 'red', pch = 19)
legend(-0.8,0, c("Recorded", "Simulated"), col = c("red", "grey"), pch = 19, bty = 'n')
par(mfrow=c(1,1), xpd = FALSE)

These various results all showa similar trend; roe deer stick to a relatively similar altitudes compared to the simulated trajectories. As well they seem to prefer higher altitude over lower altitude. However, this can be the result from human preference for lower altitudes…
Landuse
The next section analyses whether the roe deer have a preference for certain land use types. Please note that the following plot has double labels and a sub-optimal visualization. Sadly, we did not have enough time to figure these issues out. We hope you will forgive us these flaws!
# variables
colorsAnimals <- c("red","blue", "orange", "yellow", "purple")
colorsLandUse <- c('white','azure3', 'azure3', 'azure4','azure4','bisque4','bisque4','chartreuse', 'chartreuse2','chartreuse2','chartreuse3','darkolivegreen1', 'darkolivegreen1','darkolivegreen','darkolivegreen','darkorange2','darkorange2','darkgoldenrod3','darkcyan', 'darkslategray1')
names <- list(c("Agostino", "Allessandra", "Daiela", " Decimo", "Sandro"))
# copy landuse
landUseTest <- landUse
# start for reclassification table
from <- 1
to <- as.integer()
start <- 1
clas <- as.integer()
# make reclassification table to remove double lables
for (label in 1:(length(landUseLegend$LABEL2)-1)){
thisone <- landUseLegend$LABEL2[label]
nextone <- landUseLegend$LABEL2[label+1]
# check if label is same as next one
if (!thisone == nextone){
to <- c(to,label)
from <- c(from, label+1)
}
}
# add last number to get same length
to <- c(to,length(landUseLegend$LABEL2))
# create the reclassificatin table
rcl <- cbind(from, to, to)
# reclassify
landUseTest <- reclassify(landUseTest, rcl)
# ratify to get labels
landUseTest <- ratify(landUseTest)
rat <- levels(landUseTest)[[1]]
rat2 <- left_join(rat, landUseLegend, by = c("ID" = "GRID_CODE"))
rat2drop <- rat2[,c("ID","LABEL2")]
levels(landUseTest) <- rat2drop
# plot
levelplot(landUseTest, col.regions= colorsLandUse, opacity = 0.3, main = "Landuse of recorded roe deer locations", margin = FALSE, par.settings=myTheme, xlim = c(647000, 670000), key = list(space = 'bottom', points = list(lty = 1, col = colorsAnimals), text = names )) +
latticeExtra::layer({
trajectAgostinoZone32 <- spTransform(trajectAgostino, CRS(proj4zone32))
sp.lines(trajectAgostinoZone32, col = 'red')}) +
latticeExtra::layer({
trajectAllessandraZone32 <- spTransform(trajectAlessandra, CRS(proj4zone32))
sp.lines(trajectAllessandraZone32, col = 'blue')}) +
latticeExtra::layer({
trajectDanielaZone32 <- spTransform(trajectDaniela, CRS(proj4zone32))
sp.lines(trajectDanielaZone32, col = 'orange')}) +
latticeExtra::layer({
trajectDecimoZone32 <- spTransform(trajectDecimo, CRS(proj4zone32))
sp.lines(trajectDecimoZone32, col = 'yellow')}) +
latticeExtra::layer({
trajectSandroZone32 <- spTransform(trajectSandro, CRS(proj4zone32))
sp.lines(trajectSandroZone32, col = 'purple')})

The above map does not give us a very clear impression as to whether our animals prefer certain types of landuse. However, it does clearly show that the homerange of our animals mostly consists of forest and pasture.
Barplots may provide a clearer indication as to whether our animals have a preference for particular types of landuse:
# add legend to land use matrix for recorded and simulated data
simLandCombiDFLegend <- addLegend(simLandCombi, legend = landUseLegend, animalNames = animalNames)
# loop over the matrices for the different animals
for (animal in 1:length(animalNames)){
# group based on ind (recorded / number of simulations)
groupedLandUseAnimal <- as.data.frame(simLandCombiDFLegend[[animal]])
groupedLandUseCount <- groupedLandUseAnimal %>% group_by(ind, LABEL2) %>% summarise(count = n())
# create histogram
assign(paste0("h",animal),ggplot(data=groupedLandUseCount, aes(x=LABEL2, y=count, fill=ind)) +
geom_bar(stat="identity", position=position_dodge()) + ggtitle(paste("Land use of", animalNames[animal])) + xlab(NULL) + theme(axis.text.x = element_text(angle = 11, hjust = 1)))
}
grid.arrange(h1,h2, layout_matrix = rbind(c(1,1),c(2,2)))

grid.arrange(h3,h4, layout_matrix = rbind(c(1,1),c(2,2)))

grid.arrange(h5, layout_matrix = rbind(c(1,1),c(2,2)))

These plots confirm that our animals mostly reside in forest and pasture areas. Our simulated trajectories provide similar results to the recorded movement, which may explained by the fact that these landuse classes are prevalent in the area in which our animals live. The fact that this is their preferred home range does suggest that our roe deer love their strolls through forest and pasture!
Conclusion
This project has compared recorded and simulated roe deer movement in the area of Trento, Italy. It has analysed to what extent elevation and landuse can explain roe deer movement in the area. The results of the analysis suggest that the roe deer stick to a relatively small home range and stable altitude compared to the simulated locations. Roe deer had a preference for forest and pasture. However, the difference with simulated data is small, due to the high prevalence of these land use types in the home range of the roe deer.
# disconnect database
dbDisconnect(movementDB)
References
Urbano, F., & Cagnacci, F. (2014). Spatial database for GPS wildlife tracking data. Springer International Publishing.
LS0tCnRpdGxlOiAiRXhwbGFpbmluZyByb2UgZGVlciBtb3ZlbWVudCBpbiB0aGUgSXRhbGlhbiBhbHBzIgphdXRob3I6IEFubmUtSnV1bCBXZWxzaW5rIGFuZCBNYXJyaXQgTGVlbnN0cmEKZGF0ZTogMzEgSmFudWFyeSAyMDE5Cm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KVGhpcyBwcm9qZWN0IGludmVzdGlnYXRlcyBtb3ZlbWVudCBvZiBHUFMgY29sbGFyZCByb2UgZGVlciBpbiB0aGUgYXJlYSBvZiBUcmVudG8sIEl0YWx5LiBJdCBjb21wYXJlcyByZWNvcmRlZCBHUFMgZGF0YSBvZiBmaXZlIGFuaW1hbHMgKEFnb3N0aW5vLCBBbGVzc2FuZHJhLCBEYW5pZWxhLCBEZWNpbW8sIGFuZCBTYW5kcm8pIHdpdGggc2ltdWxhdGVkIHJvZSBkZWVyIHRyYWplY3RvcmllcyBpbiBvcmRlciB0byBhc3Nlc3MgdG8gd2hhdCBleHRlbnQgcm9lIGRlZXIgbW92ZW1lbnQgY2FuIGJlIGV4cGxhaW5lZCBieSBhbHRpdHVkZSBhbmQvb3IgbGFuZCB1c2UuIFRoZSByZXN1bHRzIGZyb20gdGhpcyBwcm9qZWN0IHNob3cgdGhhdCB0aGUgcm9lIGRlZXIgc3RpY2sgdG8gYSByZWxhdGl2ZWx5IHNtYWxsIGhvbWUgcmFuZ2UgYW5kIHN0YWJsZSBhbHRpdHVkZSBjb21wYXJlZCB0byB0aGUgc2ltdWxhdGVkIGxvY2F0aW9ucy4gUm9lIGRlZXIgaGFkIGEgcHJlZmVyZW5jZSBmb3IgZm9yZXN0IGFuZCBwYXN0dXJlLiBIb3dldmVyLCB0aGUgZGlmZmVyZW5jZSB3aXRoIHNpbXVsYXRlZCBkYXRhIGlzIHNtYWxsLCB3aGljaCBjYW4gYmUgZXhwbGFpbmVkIGJ5IHRoZSBoaWdoIHByZXZhbGVuY2Ugb2YgdGhlc2UgbGFuZCB1c2UgdHlwZXMgaW4gdGhlIGhvbWUgcmFuZ2Ugb2YgdGhlIHJvZSBkZWVyLgoKIVtHUFMtY29sbGFyZWQgcm9lIGRlZXJdKC4vaW1hZ2Uvcm9lRGVlci5qcGcpCgojIyBQcmVwYXJlIHdvcmtpbmcgZW52aXJvbm1lbnQKYGBge3J9CiMgY2hlY2sgaWYgbGlicmFyaWVzIGFyZSBpbnN0YWxsZWQKaWYgKCFyZXF1aXJlKCJkcGx5ciIpKSBpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpCmlmICghcmVxdWlyZSgic3AiKSkgaW5zdGFsbC5wYWNrYWdlcygic3AiKQppZiAoIXJlcXVpcmUoInNmIikpIGluc3RhbGwucGFja2FnZXMoInNmIikKaWYgKCFyZXF1aXJlKCJEQkkiKSkgaW5zdGFsbC5wYWNrYWdlcygiREJJIikKaWYgKCFyZXF1aXJlKCJSU1FMaXRlIikpIGluc3RhbGwucGFja2FnZXMoIlJTUUxpdGUiKQppZiAoIXJlcXVpcmUoInJhc3RlciIpKSBpbnN0YWxsLnBhY2thZ2VzKCJyYXN0ZXIiKQppZiAoIXJlcXVpcmUoImFkZWhhYml0YXRMVCIpKSBpbnN0YWxsLnBhY2thZ2VzKCJhZGVoYWJpdGF0TFQiKQppZiAoIXJlcXVpcmUoImx1YnJpZGF0ZSIpKSBpbnN0YWxsLnBhY2thZ2VzKCJsdWJyaWRhdGUiKQppZiAoIXJlcXVpcmUoImdncGxvdDIiKSkgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCmlmICghcmVxdWlyZSgiZ3JpZEV4dHJhIikpIGluc3RhbGwucGFja2FnZXMoImdyaWRFeHRyYSIpCmlmICghcmVxdWlyZSgibGVhZmxldCIpKSBpbnN0YWxsLnBhY2thZ2VzKCJsZWFmbGV0IikKaWYgKCFyZXF1aXJlKCJybGlzdCIpKSBpbnN0YWxsLnBhY2thZ2VzKCJybGlzdCIpCmlmICghcmVxdWlyZSgicmFzdGVyVmlzIikpIGluc3RhbGwucGFja2FnZXMoInJhc3RlclZpcyIpCmBgYAoKYGBge3J9CiMgbG9hZCBsaWJyYXJpZXMKbGlicmFyeShkcGx5cikKbGlicmFyeShzcCkKbGlicmFyeShzZikKbGlicmFyeShEQkkpCmxpYnJhcnkocmFzdGVyKQpsaWJyYXJ5KGFkZWhhYml0YXRMVCkKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkobGVhZmxldCkKbGlicmFyeShybGlzdCkKbGlicmFyeShyYXN0ZXJWaXMpCmBgYAoKYGBge3J9CiMgaW1wb3J0IGZ1bmN0aW9ucwpzb3VyY2UoIlIvcmV0cmlldmVEYXRhLlIiKQpzb3VyY2UoIlIvc2F2ZURhdGFJbkRCLlIiKQpzb3VyY2UoIlIvc2ltdWxhdGVNb3ZlbWVudC5SIikKc291cmNlKCJSL2NyZWF0ZVNwYXRpYWxMaW5lLlIiKQpzb3VyY2UoIlIvZXh0cmFjdFJhc3RlclZhbHVlcy5SIikKc291cmNlKCJSL3Bsb3RQcm9maWxlcy5SIikKc291cmNlKCJSL2NvbWJpbmVTaW1UcmFjay5SIikKc291cmNlKCJSL3N1bVN0YXRzLlIiKQpzb3VyY2UoIlIvYm94cGxvdFByb2ZpbGVzLlIiKQpzb3VyY2UoIlIvYWRkTGVnZW5kLlIiKQpgYGAKCmBgYHtyfQojIHByb2plY3QgdmFyaWFibGVzCgojIGRvd25sb2FkbGlua3MKbW92ZW1lbnREYXRhVVJMID0gImV4dHJhcy5zcHJpbmdlci5jb20vMjAxNC85NzgtMy0zMTktMDM3NDItNC90cmFja2luZ0RCX2RhdGFzZXRzLnppcCIKZW52aXJvbm1lbnRhbFVSTCA9ICJodHRwczovL2RyaXZlLmdvb2dsZS5jb20vdWM/ZXhwb3J0PWRvd25sb2FkJmlkPTFuYjdxOFRRR0FrelRjR3RTTVMwTmlnX0RBaEIybENsSiIKCmxhbmRVc2VMZWdlbmRVUkwgID0gImh0dHBzOi8vd3d3LmVlYS5ldXJvcGEuZXUvZGF0YS1hbmQtbWFwcy9kYXRhL2NvcmluZS1sYW5kLWNvdmVyLTIwMDYtcmFzdGVyLTEvY29yaW5lLWxhbmQtY292ZXItY2xhc3Nlcy1hbmQvY2xjX2xlZ2VuZC5jc3YvYXRfZG93bmxvYWQvZmlsZSIKCiMgcHJvamVjdGlvbnMKcHJvajRXR1M4NCA8LSAiK3Byb2o9bG9uZ2xhdCArZGF0dW09V0dTODQgK25vX2RlZnMiCnByb2o0em9uZTMyIDwtICIrcHJvaj11dG0gK3pvbmU9MzIgK2RhdHVtPVdHUzg0ICt1bml0cz1tICtub19kZWZzIgpwcm9qNE1lcmNhdG9yIDwtICIrcHJvaj1tZXJjICthPTYzNzgxMzcgK2I9NjM3ODEzNyArbGF0X3RzPTAuMCArbG9uXzA9MC4wICt4XzA9MC4wICt5XzA9MCAraz0xLjAgK3VuaXRzPW0gK25hZGdyaWRzPUBudWxsICt3a3RleHQgICtub19kZWZzIgpgYGAKCiMjIE9idGFpbiBkYXRhCiFbR29vZ2xlIEVhcnRoIGRhdGEgY29sbGVjdGlvbl0oLi9pbWFnZS9nb29nbGVFYXJ0aENvZGUucG5nKQoKYGBge3J9CiMgZG93bmxvYWQgbW92ZW1lbnQgZGF0YSBhbmQgdW56aXAKZm9sZGVyID0gImRhdGEiCnJldHJpZXZlRGF0YShtb3ZlbWVudERhdGFVUkwsIGZvbGRlciwgdW56aXAgPSBUUlVFKQoKIyBkb3dubG9hZCBlbnZpcm9ubWVudGFsIGRhdGEgYW5kIHVuemlwCnJldHJpZXZlRGF0YShlbnZpcm9ubWVudGFsVVJMLCBmb2xkZXIsIHVuemlwID0gVFJVRSkKCiMgZG93bmxvYWQgbGVnZW5kIGZvciBjb3JpbmUgbGFuZCBjb3ZlciAobGFuZFVzZSkKcmV0cmlldmVEYXRhKGxhbmRVc2VMZWdlbmRVUkwsIGZvbGRlciwgZmlsZW5hbWUgPSAibGFuZFVzZUxlZ2VuZC5jc3YiKQpgYGAKCmBgYHtyfQojIExvYWQgZW52aXJvbm1lbnRhbCBkYXRhIHRvIGdsb2JhbCBlbnZpcm9ubWVudApERU0gPC0gcmFzdGVyKGxpc3QuZmlsZXMocGF0aCA9ICJkYXRhL0dvb2dsZUVhcnRoRGF0YSIsIHBhdHRlcm4gPSBnbG9iMnJ4KCcqREVNKi50aWYnKSwgZnVsbC5uYW1lcyA9IFRSVUUpKQpsYW5kc2F0IDwtIGJyaWNrKGxpc3QuZmlsZXMocGF0aCA9ICJkYXRhL0dvb2dsZUVhcnRoRGF0YSIsIHBhdHRlcm4gPSBnbG9iMnJ4KCcqTGFuZHNhdCoudGlmJyksIGZ1bGwubmFtZXMgPSBUUlVFKSkKbGFuZFVzZSA8LSByYXN0ZXIobGlzdC5maWxlcyhwYXRoID0gImRhdGEvR29vZ2xlRWFydGhEYXRhIiwgcGF0dGVybiA9IGdsb2IycngoJypMYW5kVXNlKi50aWYnKSwgZnVsbC5uYW1lcyA9IFRSVUUpKQpzbG9wZSA8LSByYXN0ZXIobGlzdC5maWxlcyhwYXRoID0gImRhdGEvR29vZ2xlRWFydGhEYXRhIiwgcGF0dGVybiA9IGdsb2IycngoJypTbG9wZSoudGlmJyksIGZ1bGwubmFtZXMgPSBUUlVFKSkKbGFuZFVzZUxlZ2VuZCA8LSByZWFkLmNzdihsaXN0LmZpbGVzKHBhdGggPSBmb2xkZXIsIHBhdHRlcm4gPSBnbG9iMnJ4KCcqLmNzdicpLCBmdWxsLm5hbWVzID0gVFJVRSkpCmBgYAoKIyMgRGF0YWJhc2UgbWFuYWdlbWVudApXZSB1c2UgYW4gZXhhbXBsZSBkYXRhc2V0IG9mIHJvZSBkZWVyIG1vdmVtZW50IGZyb20gYSBib29rIGFib3V0IHNwYXRpYWwgZGF0YWJhc2UgbWFuYWdlbWVudCAoVXJiYW5vIGFuZCBDYWduYWNjaSwgMjAxNCkuIFRoZSBkYXRhIGFyZSB0aHVzIGRlc2lnbmVkIGZvciB1c2UgaW4gYSBkYXRhYmFzZSBhbmQgc2V0IHVwIGFzIGludGVybGlua2luZyBkYXRhc2V0cy4gRGlyZWN0IHVzZSBpbiBSIGlzIHBvc3NpYmxlLCBidXQgdW5kZXNpcmFibGUgZHVlIHRvIGEgbGFjayBvZiBzdHJ1Y3R1cmUuIFRoZXJlZm9yZSwgd2Ugc2V0IHVwIGFuIFNRTGl0ZSBkYXRhYmFzZSBpbiBtZW1vcnkgdG8gcHJvY2VzcyB0aGUgZGF0YS4KCmBgYHtyfQojIGNyZWF0ZSBkYXRhYmFzZSBjb25uZWN0aW9uCm1vdmVtZW50REIgPC0gZGJDb25uZWN0KFJTUUxpdGU6OlNRTGl0ZSgpLCAiIikKCiMgZ2V0IGZpbGVzCmdwc0RhdGEgPC0gbGlzdC5maWxlcyhwYXRoID0gImRhdGEvdHJhY2tpbmdfZGIvZGF0YS9zZW5zb3JzX2RhdGEvIiwgcGF0dGVybiA9IGdsb2IycngoJ0dTTTAqLmNzdicpLCBmdWxsLm5hbWVzID0gVFJVRSkKc2Vuc29yc0FuaW1hbHMgPC0gbGlzdC5maWxlcyhwYXRoID0gImRhdGEvdHJhY2tpbmdfZGIvZGF0YS9zZW5zb3JzX2FuaW1hbHMvIiwgcGF0dGVybiA9IGdsb2IycngoJyouY3N2JyksIGZ1bGwubmFtZXMgPSBUUlVFKQpzZW5zb3JzIDwtIGxpc3QuZmlsZXMocGF0aCA9ICJkYXRhL3RyYWNraW5nX2RiL2RhdGEvc2Vuc29ycy8iLCBwYXR0ZXJuID0gZ2xvYjJyeCgnKi5jc3YnKSwgZnVsbC5uYW1lcyA9IFRSVUUpCmFuaW1hbHMgPC0gbGlzdC5maWxlcyhwYXRoID0gImRhdGEvdHJhY2tpbmdfZGIvZGF0YS9hbmltYWxzLyIsIHBhdHRlcm4gPSBnbG9iMnJ4KCcqLmNzdicpLCBmdWxsLm5hbWVzID0gVFJVRSkKCiMgc3BlY2lmeSBjb2x1bW4gbmFtZXMgZm9yIGRhdGFiYXNlIHRhYmxlcwpncHNEYXRhQ29sdW1uTmFtZXMgPC0gYygiZ3BzU2Vuc29yc0NvZGUiLCJsaW5lTm8iLCAidXRjRGF0ZSIsICJ1dGNUaW1lIiwgImxtdERhdGUiLCAibG10VGltZSIsICJlY2VmWCIsICJlY2VmWSIsImVjZWZaIiwgImxhdGl0dWRlIiwgImxvbmdpdHVkZSIsIAoiaGVpZ2h0IiwgImRvcCIsICJuYXYiLCAidmFsaWRhdGVkIiwgInNhdHNVc2VkIiwgImNoMDFTYXRJZCIsICJjaDAxU2F0Q25yIiwgImNoMDJTYXRJZCIsICJjaDAyU2F0Q25yIiwgImNoMDNTYXRJZCIsICJjaDAzU2F0Q25yIiwgImNoMDRTYXRJZCIsICJjaDA0U2F0Q25yIiwgImNoMDVTYXRJZCIsICJjaDA1U2F0Q25yIiwgImNoMDZTYXRJZCIsICJjaDA2U2F0Q25yIiwgImNoMDdTYXRJZCIsICJjaDA3U2F0Q25yIiwgImNoMDhTYXRJZCIsICJjaDA4U2F0Q25yIiwgImNoMDlTYXRJZCIsICJjaDA5U2F0Q25yIiwgImNoMTBTYXRJZCIsICJjaDEwU2F0Q25yIiwgImNoMTFTYXRJZCIsICJjaDExU2F0Q25yIiwgImNoMTJTYXRJZCIsICJjaDEyU2F0Q25yIiwgIm1haW5Wb2wiLCAiYnVWb2wiLCAidGVtcCIsICJlYXN0aW5nIiwgIm5vcnRoaW5nIiwgInJlbWFya3MiKQpzZW5zb3JzQW5pbWFsc0NvbHVtbk5hbWVzIDwtIGMoImFuaW1hbHNJZCIsImdwc1NlbnNvcnNJZCIsInN0YXJ0VGltZSIsIkVuZFRpbWUiLCJub3RlcyIpCnNlbnNvcnNDb2x1bW5OYW1lcyA8LWMoImdwc1NlbnNvcnNJZCIsICJncHNTZW5zb3JzQ29kZSIsICJwdXJjaGFzZURhdGUiLCAiZnJlcXVlbmN5IiwgInZlbmRvciIsIm1vZGVsIiwic2ltIikKYW5pbWFsc0NvbHVtbk5hbWVzIDwtIGMoImFuaW1hbHNJZCIsICJhbmltYWxzQ29kZSIsICJuYW1lIiwic2V4IiwiYWdlQ2xhc3NDb2RlIiwgInNwZWNpZXNDb2RlIikKCiMgc2F2ZSBkYXRhIGluIGRhdGFiYXNlCnNhdmVEYXRhSW5EQihncHNEYXRhLCBtb3ZlbWVudERCLCAiZ3BzRGF0YSIsIGdwc0RhdGFDb2x1bW5OYW1lcywgVFJVRSkKc2F2ZURhdGFJbkRCKHNlbnNvcnNBbmltYWxzLCBtb3ZlbWVudERCLCAic2Vuc29yc0FuaW1hbHMiLCBzZW5zb3JzQW5pbWFsc0NvbHVtbk5hbWVzLCBGQUxTRSkKc2F2ZURhdGFJbkRCKHNlbnNvcnMsIG1vdmVtZW50REIsICJzZW5zb3JzIiwgc2Vuc29yc0NvbHVtbk5hbWVzLCBGQUxTRSkKc2F2ZURhdGFJbkRCKGFuaW1hbHMsIG1vdmVtZW50REIsICJhbmltYWxzIiwgYW5pbWFsc0NvbHVtbk5hbWVzLCBGQUxTRSkKYGBgCgpUaGUgZGF0YWJhc2UgY2FuIGJlIHF1ZXJpZWQgd2l0aCBTUUwuIFNpbmNlIHdlIHdhbnQgdG8gbGluayB0aGUgR1BTIGRhdGEgd2l0aCBzcGVjaWZpYyBhbmltYWxzIHdlIG5lZWQgdG8gam9pbiB0aGVzZSB0YWJsZXMuIEhvd2V2ZXIsIHRoZXNlIHRhYmxlcyBkbyBub3QgaGF2ZSBhbnkgY29tbW9uIGZpZWxkcyB0aGF0IGNhbiBiZSB1c2VkIGZvciBhIHN0cmFpZ2h0Zm9yd2FyZCBqb2luLiBFbWJlZGRpbmcgb2YgU1FMIHN0YXRlbWVudHMgYWxsb3dzIHVzIHRvIGdldCB0byB0aGUgcmVxdWlyZWQgY29tYmluYXRpb24gb2YgZGF0YS4gCgpgYGB7cn0KIyBxdWVyeSBkYXRhIGZyb20gZGF0YWJhc2UKcXVlcnkgPC0gJwpTRUxFQ1QKYW5pbWFscy5uYW1lLAphbmltYWxzLnNleCwKZGF0YVdpdGhBbmltYWxJZC51dGNEYXRlLCBkYXRhV2l0aEFuaW1hbElkLnV0Y1RpbWUsIApkYXRhV2l0aEFuaW1hbElkLmxhdGl0dWRlLCBkYXRhV2l0aEFuaW1hbElkLmxvbmdpdHVkZSwKZGF0YVdpdGhBbmltYWxJZC5oZWlnaHQKRlJPTQogIChTRUxFQ1QgCiAgZGF0YVdpdGhTZW5zb3JJZC5ncHNTZW5zb3JzQ29kZSwgCiAgZGF0YVdpdGhTZW5zb3JJZC51dGNEYXRlLCBkYXRhV2l0aFNlbnNvcklkLnV0Y1RpbWUsIAogIGRhdGFXaXRoU2Vuc29ySWQubGF0aXR1ZGUsIGRhdGFXaXRoU2Vuc29ySWQubG9uZ2l0dWRlLCAKICBkYXRhV2l0aFNlbnNvcklkLmhlaWdodCwKICBkYXRhV2l0aFNlbnNvcklkLmdwc1NlbnNvcnNJZCwgCiAgc2Vuc29yc0FuaW1hbHMuYW5pbWFsc0lkIAogIEZST00gCiAgICAoU0VMRUNUIAogICAgZ3BzRGF0YS5ncHNTZW5zb3JzQ29kZSwgCiAgICBncHNEYXRhLnV0Y0RhdGUsIGdwc0RhdGEudXRjVGltZSwgCiAgICBncHNEYXRhLmxhdGl0dWRlLCBncHNEYXRhLmxvbmdpdHVkZSwgCiAgICBncHNEYXRhLmhlaWdodCwKICAgIHNlbnNvcnMuZ3BzU2Vuc29yc0lkIAogICAgRlJPTSAKICAgIGdwc0RhdGEgCiAgICBMRUZUIEpPSU4gCiAgICBzZW5zb3JzIE9OIGdwc0RhdGEuZ3BzU2Vuc29yc0NvZGUgPSBzZW5zb3JzLmdwc1NlbnNvcnNDb2RlKSBBUyBkYXRhV2l0aFNlbnNvcklkIAogIExFRlQgSk9JTiAKICBzZW5zb3JzQW5pbWFscyBPTiBkYXRhV2l0aFNlbnNvcklkLmdwc1NlbnNvcnNJZCA9IHNlbnNvcnNBbmltYWxzLmdwc1NlbnNvcnNJZCkgQVMgZGF0YVdpdGhBbmltYWxJZCAKTEVGVCBKT0lOCmFuaW1hbHMgT04gZGF0YVdpdGhBbmltYWxJZC5hbmltYWxzSWQgPSBhbmltYWxzLmFuaW1hbHNJZAo7JwoKc2VsZWN0ZWRNb3ZlbWVudERhdGEgPC0gZGJHZXRRdWVyeShtb3ZlbWVudERCLCBxdWVyeSkKYGBgCgojIyBQcmUtcHJvY2Vzc2luZwpBdCB0aGlzIHBvaW50IHdlIGhhdmUgdGhlIGRhdGEgd2UgbmVlZC4gSG93ZXZlciwgYWxsIGRhdGEgaXMgc3RvcmVkIGFzIHN0cmluZ3MuIFRoZSBjb3JyZWN0IGNsYXNzZXMgYXJlIGFzc2lnbmVkLCBiZWZvcmUgd2UgY2FuIGNyZWF0ZSBhIGdlb21ldHJ5IG91dCBvZiB0aGUgbGF0aXR1ZGUgYW5kIGxvbmdpdHVkZSBjb2x1bW5zLiBXZSBjaG9vc2UgdGhlIFdHUzg0IHpvbmUgMzIgKEVQU0c6MzI2MzIpIGFzIGNvb3JkaW5hdGUgc3lzdGVtIGFzIGl0IHByb3ZpZGVzIGVub3VnaCBkZXRhaWwgZm9yIG91ciBhbmFseXNlcy4gCgpgYGB7cn0KIyBjb3JyZWN0IGNsYXNzZXMKc2VsZWN0ZWRNb3ZlbWVudERhdGEkc2V4IDwtIGZhY3RvcihzZWxlY3RlZE1vdmVtZW50RGF0YSRzZXgpCmNsYXNzKHNlbGVjdGVkTW92ZW1lbnREYXRhJGxhdGl0dWRlKSA8LSAibnVtZXJpYyIKY2xhc3Moc2VsZWN0ZWRNb3ZlbWVudERhdGEkbG9uZ2l0dWRlKSA8LSAibnVtZXJpYyIKY2xhc3Moc2VsZWN0ZWRNb3ZlbWVudERhdGEkaGVpZ2h0KSA8LSAibnVtZXJpYyIKc2VsZWN0ZWRNb3ZlbWVudERhdGEkZGF0ZSA8LSBkbXlfaG1zKHBhc3RlKHNlbGVjdGVkTW92ZW1lbnREYXRhJHV0Y0RhdGUsIHNlbGVjdGVkTW92ZW1lbnREYXRhJHV0Y1RpbWUpLCB0eiA9ICJVVEMiKQojIHJlbW92ZSByZWR1bmRhbnQgY29sdW1ucwpzZWxlY3RlZE1vdmVtZW50RGF0YVszOjRdIDwtIGxpc3QoTlVMTCkKCiMgcmVtb3ZlIHJvd3Mgd2l0aCBOQSBmb3IgbG9jYXRpb24Kc2VsZWN0ZWRNb3ZlbWVudERhdGFOb05BIDwtIHNlbGVjdGVkTW92ZW1lbnREYXRhWyFpcy5uYShzZWxlY3RlZE1vdmVtZW50RGF0YSRsYXRpdHVkZSkgfCAhaXMubmEoc2VsZWN0ZWRNb3ZlbWVudERhdGEkbG9uZ2l0dWRlKSxdCgojIGNyZWF0ZSBzcGF0aWFsIGRhdGEgZnJhbWUgcHJvamVjdGVkIGluIFdHUzg0IHpvbmUgMzIKY29vcmRzIDwtIHNlbGVjdGVkTW92ZW1lbnREYXRhTm9OQVssYyg0OjMpXQpXR1M4NG1vdmVtZW50U0RGIDwtIFNwYXRpYWxQb2ludHNEYXRhRnJhbWUoY29vcmRzID0gY29vcmRzLCBkYXRhID0gc2VsZWN0ZWRNb3ZlbWVudERhdGFOb05BLCBwcm9qNHN0cmluZyA9IENSUyhwcm9qNFdHUzg0KSkKbW92ZW1lbnRTREYgPC0gc3BUcmFuc2Zvcm0oV0dTODRtb3ZlbWVudFNERiwgQ1JTKHByb2o0em9uZTMyKSkKCiMgY3JlYXRlIHRyYWplY3Rvcmllcwptb3ZlbWVudFRyYWplY3RvcmllcyA8LSBhcy5sdHJhaih4eSA9IGNvb3JkaW5hdGVzKG1vdmVtZW50U0RGKSwgZGF0ZSA9IG1vdmVtZW50U0RGJGRhdGUsIGlkID0gbW92ZW1lbnRTREYkbmFtZSkKCiMgYW5kIGNyZWF0ZSBhIGRhdGFmcmFtZSB0byBncm91cCBvdXIgZGF0YSBhbmQgYWRkIGhlaWdodCBpbmZvcm1hdGlvbgpkYXRhZnJhbWVUcmFqZWN0b3JpZXMgPC0gbGQobW92ZW1lbnRUcmFqZWN0b3JpZXMpCmdyb3VwcyA8LSBkYXRhZnJhbWVUcmFqZWN0b3JpZXMgJT4lIG11dGF0ZShoZWlnaHQgPSBtb3ZlbWVudFNERiRoZWlnaHQpICU+JSBncm91cF9ieShpZCkKdHJhamVjdG9yaWVzIDwtIGRsKGdyb3VwcykKYGBgCgpXZSBhcmUgY3VyaW91cyB3aGVyZSAib3VyIiByb2UgZGVlciBhcmUgZ29pbmchIApGb3IgdmlzdWFsaXphdGlvbiBwdXJwb3NlcyB3ZSBuZWVkIHRvIGNyZWF0ZSBzcGF0aWFsIGxpbmVzIG9mIHRoZSBHUFMgcmVjb3JkZWQgdHJhamVjdG9yaWVzLgoKYGBge3J9CiMgc2VsZWN0IGRpc3RpbmN0IGFuaW1hbHMKYW5pbWFsTmFtZXMgPC0gZGlzdGluY3QoZ3JvdXBzLCBpZClbWzFdXQoKZm9yIChhbmltYWwgaW4gYW5pbWFsTmFtZXMpewogICMgZ2V0IGxvY2F0aW9uIGRhdGEgZnJvbSBudGggYW5pbWFsCiAgbG9jYXRpb25kYXRhaW5pdCA8LSBncm91cHNbKGdyb3VwcyRpZCA9PSBhbmltYWwpLF0KICAKICAjIGNyZWF0ZSBzcGF0aWFsIGxpbmUKICBhc3NpZ24ocGFzdGUwKCJ0cmFqZWN0aW5pdCIsYW5pbWFsKSwgY3JlYXRlU3BhdGlhbExpbmUobG9jYXRpb25kYXRhID0gbG9jYXRpb25kYXRhaW5pdCwgcHJvajRkYXRhZnJhbWUgPSBwcm9qNHpvbmUzMiwgcHJvajRsaW5lID0gcHJvajRXR1M4NCwgbGluZUlkID0gYW5pbWFsKSkKfQoKYGBgCgpBbiBpbnRlcmFjdGl2ZSBsZWFmbGV0IG1hcCBhbGxvd3MgdXMgdG8gZXhwbG9yZSB0aGUgR1BTIHJlY29yZGVkIG1vdmVtZW50IG9mIG91ciByb2UgZGVlciwgQWdvc3Rpbm8sIEFsZXNzYW5kcmEsIERhbmllbGEsIERlY2ltbywgYW5kIFNhbmRyby4KYGBge3J9Cm0gPC0gbGVhZmxldCgpICU+JSAKICBzZXRWaWV3KGxuZz0xMS4wMzY3LCBsYXQ9NDYuMDMzMSwgem9vbSA9IDExKSAlPiUKICAjIGJhc2VsYXllcnMKICBhZGRUaWxlcyhncm91cCA9ICdTdHJlZXQgbWFwJykgJT4lICAKICBhZGRQcm92aWRlclRpbGVzKCdTdGFtZW4uVGVycmFpbicsIGdyb3VwID0gJ1RlcnJhaW4nKSAlPiUgCiAgYWRkUHJvdmlkZXJUaWxlcygnRXNyaS5Xb3JsZEltYWdlcnknLCBncm91cCA9ICdTYXRlbGxpdGUnKSAlPiUKICAjIG92ZXJsYXkgZ3JvdXBzCiAgYWRkUG9seWxpbmVzKGRhdGEgPSB0cmFqZWN0aW5pdEFnb3N0aW5vLCB3ZWlnaHQgPSAxLCBvcGFjaXR5ID0gMC44LCBjb2xvciA9ICJyZWQiLCBncm91cCA9ICdBZ29zdGlubycpICU+JSAKICBhZGRQb2x5bGluZXMoZGF0YSA9IHRyYWplY3Rpbml0QWxlc3NhbmRyYSwgd2VpZ2h0ID0gMSwgb3BhY2l0eSA9IDAuOCwgY29sb3IgPSAiYmx1ZSIsIGdyb3VwID0gJ0FsZXNzYW5kcmEnKSAlPiUgCiAgYWRkUG9seWxpbmVzKGRhdGEgPSB0cmFqZWN0aW5pdERhbmllbGEsIHdlaWdodCA9IDEsIG9wYWNpdHkgPSAwLjgsIGNvbG9yID0gIm9yYW5nZSIsIGdyb3VwID0gJ0RhbmllbGEnKSAlPiUgCiAgYWRkUG9seWxpbmVzKGRhdGEgPSB0cmFqZWN0aW5pdERlY2ltbywgd2VpZ2h0ID0gMSwgb3BhY2l0eSA9IDAuOCwgY29sb3IgPSAieWVsbG93IiwgZ3JvdXAgPSAnRGVjaW1vJykgJT4lIAogIGFkZFBvbHlsaW5lcyhkYXRhID0gdHJhamVjdGluaXRTYW5kcm8sIHdlaWdodCA9IDEsIG9wYWNpdHkgPSAwLjgsIGNvbG9yID0gInB1cnBsZSIsIGdyb3VwID0gJ1NhbmRybycpICU+JSAKICBhZGRMYXllcnNDb250cm9sKAogICAgYmFzZUdyb3VwcyA9IGMoJ1N0cmVldCBtYXAnLCAnVGVycmFpbicsICdTYXRlbGxpdGUnKSwKICAgIG92ZXJsYXlHcm91cHMgPSBjKCdBZ29zdGlubycsICdBbGVzc2FuZHJhJywgJ0RhbmllbGEnLCAnRGVjaW1vJywgJ1NhbmRybycpLAogICAgb3B0aW9ucyA9IGxheWVyc0NvbnRyb2xPcHRpb25zKGNvbGxhcHNlZCA9IEZBTFNFKQogICkKbSAKCmBgYAoKT29wcyEgVGhlIGRhdGEgY2xlYXJseSBjb250YWluIHNvbWUgb3V0bGllcnMuIFRoZXNlIG5lZWQgdG8gYmUgcmVtb3ZlZCBpbiBvcmRlciB0byBwZXJmb3JtIHJlbGlhYmxlIGFuYWx5c2VzLiBCdXQgaG93IGRvIHdlIGRlZmluZSB3aGljaCBwb2ludHMgYXJlIG91dGxpZXJzPyBXZSBsb29rIGF0IGJveHBsb3RzIG9mIGRpZmZlcmVudCB2YXJpYWJsZXMgaW4gb3JkZXIgdG8gZGV0ZXJtaW5lIGEgc3VpdGFibGUgbWV0aG9kIHRvIGlkZW50aWZ5IG91dGxpZXJzLiAKCmBgYHtyfQojIHBsb3QKcDEgPC0gZ2dwbG90KGdyb3VwcywgYWVzKHg9aWQsIHk9eCwgZmlsbCA9IGlkKSkgKyBnZW9tX2JveHBsb3QoYWxwaGE9MC4yKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBnZ3RpdGxlKCJ4LWNvb3JkaW5hdGVzIG9mIGxvY2F0aW9ucyIpCnAyIDwtIGdncGxvdChncm91cHMsIGFlcyh4PWlkLCB5PXksIGZpbGwgPSBpZCkpICsgZ2VvbV9ib3hwbG90KGFscGhhPTAuMikgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgZ2d0aXRsZSgieS1jb29yZGluYXRlcyBvZiBsb2NhdGlvbnMiKQpwMyA8LSBnZ3Bsb3QoZ3JvdXBzLCBhZXMoeD1pZCwgeT1kaXN0LCBmaWxsID0gaWQpKSArIGdlb21fYm94cGxvdChhbHBoYT0wLjIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIGdndGl0bGUoIkRpc3RhbmNlIGJldHdlZW4gcmVsb2NhdGlvbnMiKQpwNCA8LSBnZ3Bsb3QoZ3JvdXBzLCBhZXMoeD1pZCwgeT1hYnMuYW5nbGUsIGZpbGwgPSBpZCkpICsgZ2VvbV9ib3hwbG90KGFscGhhPTAuMikgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgZ2d0aXRsZSgiQWJzb2x1dGUgYW5nbGUgYmV0d2VlbiByZWxvY2F0aW9ucyIpCnA1IDwtIGdncGxvdChncm91cHMsIGFlcyh4PWlkLCB5PXJlbC5hbmdsZSwgZmlsbCA9IGlkKSkgKyBnZW9tX2JveHBsb3QoYWxwaGE9MC4yKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBnZ3RpdGxlKCJSZWxhdGl2ZSBhbmdsZSBiZXR3ZWVuIHJlbG9jYXRpb25zIikKcDYgPC0gZ2dwbG90KGdyb3VwcywgYWVzKHg9aWQsIHk9ZHQsIGZpbGwgPSBpZCkpICsgZ2VvbV9ib3hwbG90KGFscGhhPTAuMikgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgZ2d0aXRsZSgiVGltZSBiZXR3ZWVuIHJlbG9jYXRpb25zIikKCmdyaWQuYXJyYW5nZShwMSxwMixwMyxwNCxwNSxwNiwgbGF5b3V0X21hdHJpeCA9IHJiaW5kKGMoMSwyKSxjKDMsNCksYyg1LDYpKSkKYGBgCgpUaGVzZSBib3hwbG90cyBzaG93IHRoZSBvdXRsaWVycyB2ZXJ5IGNsZWFybHkgaW4gdGhlIHggYW5kIHktY29vcmRpbmF0ZXMgYXMgd2VsbCBhcyB0aGUgZGlzdGFuY2UgYW5kIHRpbWUgYmV0d2VlbiByZWxvY2F0aW9ucy4gSW4gcHJldmlvdXMgc3RlcHMgd2UgcmVtb3ZlZCBzb21lIG1lYXN1cmVtZW50cyB3aXRoIE5BJ3MgZm9yIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUgdG8gYmUgYWJsZSB0byBjb252ZXJ0IHRoZSBkYXRhZnJhbWUgdG8gYSBzcGF0aWFsIGRhdGFmcmFtZS4gQXMgYSByZXN1bHQsIHRoZSB0aW1lIGJldHdlZW4gcmVsb2NhdGlvbnMgaXMgbm90IDEwMCUgYWNjdXJhdGUuIFdlIHdpbGwgdGhlcmVmb3JlIHVzZSBvbmx5IHgtY29vcmRpbmF0ZXMsIHktY29vcmRpbmF0ZXMgYW5kIGRpc3RhbmNlIGJldHdlZW4gcmVsYXRpb25zIHRvIGNsZWFuIG91ciBkYXRhc2V0LiBUcmVzaG9sZHMgZm9yIHRoZSB4IGFuZCB5LWNvb3JkaW5hdGVzIGFyZSBiYXNlZCBwdXJlbHkgb24gdGhlc2UgYm94cGxvdHMuIFRvIGRldGVybWluZSB0aGUgdHJlc2hvbGQgZm9yIHRoZSBkaXN0YW5jZSB3ZSB0YWtlIGEgbG9vayBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHN0ZXBsZW5ndGhzLiAKCmBgYHtyfQojIHBsb3QgaGlzdG9ncmFtcyBvZiBkaXN0YW5jZSBiZXR3ZWVuIGxvY2F0aW9uIHBvaW50cwpwYXIobWZyb3c9YygzLCAyKSkKZm9yIChpIGluIDE6bGVuZ3RoKGlkKG1vdmVtZW50VHJhamVjdG9yaWVzKSkpewogIGhpc3QobW92ZW1lbnRUcmFqZWN0b3JpZXNbW2ldXSRkaXN0LCB4bGltID0gYygwLCA1MDAwKSwgeWxpbSA9IGMoMCwgMTUwMCksIGJyZWFrcyA9IHNlcSgwLCAxMDAwMDAwLCBieSA9IDEwMCksIHhsYWIgPSAiZGlzdGFuY2UgKG0pIiwgbWFpbiA9IHBhc3RlKCJEaXN0YW5jZSBiZXR3ZWVuIHJlbG9jYXRpb25zIGJ5IiwgaWQobW92ZW1lbnRUcmFqZWN0b3JpZXMpW2ldKSkKfQpgYGAKTG9va2luZyBhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHN0ZXBsZW5ndGhzIGFuZCB0YWtpbmcgaW50byBhY2NvdW50IHRoZSBjb25zaWRlcmF0aW9uIHRoYXQgcm9lIGRlZXIgZ2VuZXJhbGx5IGRvIG5vdCB0cmF2ZWwgZ3JlYXQgZGlzdGFuY2VzLCBhIG1vdmVkIGRpc3RhbmNlIG9mIDE1MDBtIG9yIGhpZ2hlciBpbiBvbmUgcmVsb2NhdGlvbiBpcyBjb25zaWRlcmVkIHVucmVhbGlzdGljLiAKCmBgYHtyfQojIHRyZXNob2xkcwp4TWluIDwtIDY1MDAwMAp4TWF4IDwtIDcwMDAwMAp5TWluIDwtIDUwOTI1MDAKeU1heCA8LSA1MTA3NTAwCmRpc3RNYXggPC0gMTUwMAoKIyByZW1vdmUgb3V0bGllcnMgYmFzZWQgb24geC1jb29yZGluYXRlcyBhbmQgZGlzdGFuY2UgYmV0d2VlbiByZWxvY2F0aW9ucwpncm91cHNDbGVhbmVkIDwtIGdyb3VwcyAlPiUgZmlsdGVyKHggPCB4TWF4KSAlPiUgZmlsdGVyKHggPiB4TWluKSAlPiUgZmlsdGVyKHkgPCB5TWF4KSAlPiUgZmlsdGVyKHkgPiB5TWluKSAlPiUgZmlsdGVyKGRpc3QgPCBkaXN0TWF4KQoKIyBjYXN0IGJhY2sgdG8gbHRyYWogCm1vdmVtZW50VHJhamVjdG9yaWVzQ2xlYW5lZCA8LSBkbChncm91cHNDbGVhbmVkKQpgYGAKCkZvciB2aXN1YWxpemF0aW9uIHB1cnBvc2VzIHdlIGNyZWF0ZSBTcGF0aWFsIExpbmVzIG9mIHRoZSByZWNvcmRlZCB0cmFqZWN0b3JpZXMgd2l0aG91dCBvdXRsaWVycy4KCmBgYHtyfQojIHNlbGVjdCBkaXN0aW5jdCBhbmltYWxzCmFuaW1hbE5hbWVzIDwtIGRpc3RpbmN0KGdyb3Vwc0NsZWFuZWQsIGlkKVtbMV1dCgpmb3IgKGFuaW1hbCBpbiBhbmltYWxOYW1lcyl7CiAgIyBnZXQgbG9jYXRpb24gZGF0YSBmcm9tIG50aCBhbmltYWwKICBsb2NhdGlvbmRhdGEgPC0gZ3JvdXBzQ2xlYW5lZFsoZ3JvdXBzQ2xlYW5lZCRpZCA9PSBhbmltYWwpLF0KICAKICAjIGNyZWF0ZSBzcGF0aWFsIGxpbmUKICBhc3NpZ24ocGFzdGUwKCJ0cmFqZWN0IixhbmltYWwpLCBjcmVhdGVTcGF0aWFsTGluZShsb2NhdGlvbmRhdGEgPSBsb2NhdGlvbmRhdGEsIHByb2o0ZGF0YWZyYW1lID0gcHJvajR6b25lMzIsIHByb2o0bGluZSA9IHByb2o0V0dTODQsIGxpbmVJZCA9IGFuaW1hbCkpCn0KCmBgYAoKV2UgY2FuIG5vdyB2aXN1YWxpemUgdGhlIGNsZWFuZWQgbW92ZW1lbnQgcGF0dGVybnMgb2Ygb3VyIGJlbG92ZWQgcm9lIGRlZXIhCmBgYHtyfQptIDwtIGxlYWZsZXQoKSAlPiUgCiAgc2V0Vmlldyhsbmc9MTEuMDM2NywgbGF0PTQ2LjAzMzEsIHpvb20gPSAxMSkgJT4lCiAgIyBiYXNlbGF5ZXJzCiAgYWRkVGlsZXMoZ3JvdXAgPSAnU3RyZWV0IG1hcCcpICU+JSAgCiAgYWRkUHJvdmlkZXJUaWxlcygnU3RhbWVuLlRlcnJhaW4nLCBncm91cCA9ICdUZXJyYWluJykgJT4lIAogIGFkZFByb3ZpZGVyVGlsZXMoJ0VzcmkuV29ybGRJbWFnZXJ5JywgZ3JvdXAgPSAnU2F0ZWxsaXRlJykgJT4lCiAgIyBvdmVybGF5IGdyb3VwcwogIGFkZFBvbHlsaW5lcyhkYXRhID0gdHJhamVjdEFnb3N0aW5vLCB3ZWlnaHQgPSAxLCBvcGFjaXR5ID0gMC44LCBjb2xvciA9ICJyZWQiLCBncm91cCA9ICdBZ29zdGlubycpICU+JSAKICBhZGRQb2x5bGluZXMoZGF0YSA9IHRyYWplY3RBbGVzc2FuZHJhLCB3ZWlnaHQgPSAxLCBvcGFjaXR5ID0gMC44LCBjb2xvciA9ICJibHVlIiwgZ3JvdXAgPSAnQWxlc3NhbmRyYScpICU+JSAKICBhZGRQb2x5bGluZXMoZGF0YSA9IHRyYWplY3REYW5pZWxhLCB3ZWlnaHQgPSAxLCBvcGFjaXR5ID0gMC44LCBjb2xvciA9ICJvcmFuZ2UiLCBncm91cCA9ICdEYW5pZWxhJykgJT4lIAogIGFkZFBvbHlsaW5lcyhkYXRhID0gdHJhamVjdERlY2ltbywgd2VpZ2h0ID0gMSwgb3BhY2l0eSA9IDAuOCwgY29sb3IgPSAieWVsbG93IiwgZ3JvdXAgPSAnRGVjaW1vJykgJT4lIAogIGFkZFBvbHlsaW5lcyhkYXRhID0gdHJhamVjdFNhbmRybywgd2VpZ2h0ID0gMSwgb3BhY2l0eSA9IDAuOCwgY29sb3IgPSAicHVycGxlIiwgZ3JvdXAgPSAnU2FuZHJvJykgJT4lIAogIGFkZExheWVyc0NvbnRyb2woCiAgICBiYXNlR3JvdXBzID0gYygnU3RyZWV0IG1hcCcsICdUZXJyYWluJywgJ1NhdGVsbGl0ZScpLAogICAgb3ZlcmxheUdyb3VwcyA9IGMoJ0Fnb3N0aW5vJywgJ0FsZXNzYW5kcmEnLCAnRGFuaWVsYScsICdEZWNpbW8nLCAnU2FuZHJvJyksCiAgICBvcHRpb25zID0gbGF5ZXJzQ29udHJvbE9wdGlvbnMoY29sbGFwc2VkID0gRkFMU0UpCiAgKQptIApgYGAKTm90ZSEgVGhlIGRhdGEgbWlnaHQgc3RpbGwgY29udGFpbiBhIGZldyB3cm9uZ2x5IHJlY29yZGVkIHBvaW50cyAod2UgYXJlIG5vdCBzdXJlIHdoZXRoZXIgQWdvc3Rpbm8gcmVhbGx5IHZpc2l0ZWQgaGlzIGF1bnQgaW4gU3RyYXZpbm8gZm9yIGEgY29mZmVlKS4gSG93ZXZlciwgd2UgYXJlIG5vdCBqdXN0aWZpZWQgdG8gcmVtb3ZlIHRoZXNlIHBvdGVudGlhbCBvdXRsaWVycyBvbiB0aGUgYmFzaXMgb2Ygb3VyIHByZXZpb3VzbHkgZGVmaW5lZCBjdXQtb2ZmIHBvaW50LgoKQm94cGxvdHMgYWxsb3cgZm9yIGZ1cnRoZXIgYXNzZXNzbWVudCBvZiB0aGUgY2xlYW5lZCBkYXRhLiBMb29rcyBhIGxvdCBiZXR0ZXIsIGRvZXNuJ3QgaXQ/CmBgYHtyfQojIGJveHBsb3RzCnAxIDwtIGdncGxvdChncm91cHNDbGVhbmVkLCBhZXMoeD1pZCwgeT14LCBmaWxsID0gaWQpKSArIGdlb21fYm94cGxvdChhbHBoYT0wLjIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIGdndGl0bGUoIngtY29vcmRpbmF0ZXMgb2YgbG9jYXRpb25zIikKcDIgPC0gZ2dwbG90KGdyb3Vwc0NsZWFuZWQsIGFlcyh4PWlkLCB5PXksIGZpbGwgPSBpZCkpICsgZ2VvbV9ib3hwbG90KGFscGhhPTAuMikgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsgZ2d0aXRsZSgieS1jb29yZGluYXRlcyBvZiBsb2NhdGlvbnMiKQpwMyA8LSBnZ3Bsb3QoZ3JvdXBzQ2xlYW5lZCwgYWVzKHg9aWQsIHk9ZGlzdCwgZmlsbCA9IGlkKSkgKyBnZW9tX2JveHBsb3QoYWxwaGE9MC4yKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBnZ3RpdGxlKCJEaXN0YW5jZSBiZXR3ZWVuIHJlbG9jYXRpb25zIikKcDQgPC0gZ2dwbG90KGdyb3Vwc0NsZWFuZWQsIGFlcyh4PWlkLCB5PWFicy5hbmdsZSwgZmlsbCA9IGlkKSkgKyBnZW9tX2JveHBsb3QoYWxwaGE9MC4yKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBnZ3RpdGxlKCJBYnNvbHV0ZSBhbmdsZSBiZXR3ZWVuIHJlbG9jYXRpb25zIikKcDUgPC0gZ2dwbG90KGdyb3Vwc0NsZWFuZWQsIGFlcyh4PWlkLCB5PXJlbC5hbmdsZSwgZmlsbCA9IGlkKSkgKyBnZW9tX2JveHBsb3QoYWxwaGE9MC4yKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyBnZ3RpdGxlKCJSZWxhdGl2ZSBhbmdsZSBiZXR3ZWVuIHJlbG9jYXRpb25zIikKcDYgPC0gZ2dwbG90KGdyb3Vwc0NsZWFuZWQsIGFlcyh4PWlkLCB5PWR0LCBmaWxsID0gaWQpKSArIGdlb21fYm94cGxvdChhbHBoYT0wLjIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArIGdndGl0bGUoIlRpbWUgYmV0d2VlbiByZWxvY2F0aW9ucyIpCgpncmlkLmFycmFuZ2UocDEscDIscDMscDQscDUscDYsIGxheW91dF9tYXRyaXggPSByYmluZChjKDEsMiksYygzLDQpLGMoNSw2KSkpCmBgYAoKIyMgRGF0YSB2YWxpZGF0aW9uClRoZSBkYXRhIGlzIHJlYWR5IGZvciB0aGUgYW5hbHlzZXMhCgpCZWZvcmUgd2Ugc3RhcnQgb3VyIG1vdmVtZW50IGFuYWx5c2lzLCB3ZSB3aWxsIGFzc2VzcyB0aGUgcmVsaWFiaWxpdHkgb2Ygb3VyIGRhdGEuClRoZSBhbHRpdHVkZSBtZWFzdXJlbWVudCBvZiB0aGUgR1BTIGRhdGEgbmVlZHMgdG8gYmUgdmFsaWRhdGVkIHRocm91Z2ggYSBjb21wYXJpc29uIHdpdGggdGhlIERFTS4gR1BTIGRhdGEgYXJlIG5vdCByZWxpYWJsZSBpZiBpdHMgbWVhbiBhbHRpdHVkZSBkaWZmZXJzIHNpZ25pZmljYW50bHkgZnJvbSB0aGUgREVNIHZhbHVlcyBhdCBjb3JyZXNwb25kaW5nIHNwYXRpYWwgcG9pbnRzLiAKCkEgYm94cGxvdCBhbGxvd3MgdXMgdG8gaGF2ZSBhIGZpcnN0IGxvb2sgYXQgdGhlIGRpZmZlcmVuY2UgaW4gaGVpZ2h0IG1lYXN1cmVtZW50IGJldHdlZW4gREVNIGFuZCBHUFMuCgpgYGB7cn0KIyBjYWxjdWxhdGUgREVNIGhlaWdodCB2YWx1ZXMgYXQgcG9pbnQgbG9jYXRpb25zIGZvciB3aGljaCBHUFMgaGVpZ2h0IGRhdGEgaXMgYXZhaWxhYmxlLgpoZWlnaHRERU0gPC0gZXh0cmFjdChERU0sIGFzLmRhdGEuZnJhbWUoZ3JvdXBzQ2xlYW5lZFssYygieCIsInkiKV0pLCBtZXRob2Q9J3NpbXBsZScsIG5hLnJtPVRSVUUsIGRmPVRSVUUpCmhlaWdodERFTSRhbmltYWwgPC0gdW5saXN0KGdyb3Vwc0NsZWFuZWRbLCJpZCJdKQpjb2xuYW1lcyhoZWlnaHRERU0pIDwtIGMoIklEIiwgInJhc3RlclZhbCIsICJhbmltYWwiKQoKaGVpZ2h0RGF0YSA8LSBkYXRhLmZyYW1lKGdyb3VwID0gcmVwKGMoIkRFTSIsICJHUFMiKSwgZWFjaCA9IG5yb3coaGVpZ2h0REVNKSksIGhlaWdodCA9IGMoaGVpZ2h0REVNJHJhc3RlclZhbCwgZ3JvdXBzQ2xlYW5lZCRoZWlnaHQpKQoKIyB2aXN1YWxpemUKYm94cGxvdChoZWlnaHQgfiBncm91cCwgaGVpZ2h0RGF0YSwgbWFpbiA9ICJIZWlnaHQgYm94cGxvdCBHUFMgYW5kIERFTSIsIHlsYWIgPSAiSGVpZ2h0IikKYGBgCk9vaCBubyEgVGhlIEdQUyBkYXRhIGNvbnRhaW5zIGxhcmdlIG91dGxpZXJzICh0aGUgYWxwcyBhcmUgbm90IGV2ZW4gMjAgMDAwbSBoaWdoISkuIERpZCBBbGxlc3NhbmRybyBhbHNvIGhhdmUgYSBjb2ZmZWUgaW4gb3V0ZXIgc3BhY2U/CgpBIHBhaXJlZCB0LXRlc3QgaXMgcGVyZm9ybWVkIHRvIGFzc2VzcyB0aGUgcmVsaWFiaWxpdHkgdGhlIG1lYXN1cmVtZW50cy4KYGBge3J9CiMgcGVyZm9ybSBhIHBhaXJlZCB0LXRlc3QgdG8gY29tcGFyZSBtZWFuIEdQUyBhbmQgREVNIGhlaWdodAp0VGVzdCA8LSB0LnRlc3QoaGVpZ2h0REVNJHJhc3RlclZhbCwgZ3JvdXBzQ2xlYW5lZCRoZWlnaHQsIHBhaXJlZCA9IFRSVUUsIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpCnByaW50KCJSZXN1bHRzIG9mIHRoZSBwYWlyZWQgdC10ZXN0OiIpCnRUZXN0CmBgYAoKVGhlIHBhaXJlZCB0LXRlc3QgY29uZmlybXMgdGhhdCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgKHAtdmFsdWUgPCAyLjJlLTE2KSBpbiBtZWFuIGFsdGl0dWRlIGJldHdlZW4gdGhlIEdQUyBoZWlnaHQgbWVhc3VyZW1lbnQgYW5kIHRoZSBERU0gaGVpZ2h0IHZhbHVlcy4gVGhlIG1lYW4gZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28gbWVhc3VyZW1lbnRzIGFtb3VudHMgdG8gNDEgbWV0ZXJzLiBUaGlzIGNvbmZpcm1zIG91ciBzdXNwaWNpb24gdGhhdCB0aGUgR1BTIGFsdGl0dWRlIG1lYXN1cmVtZW50cyBhcmUgbm90IGFsd2F5cyByZWxpYWJsZS4gVGhlcmVmb3JlLCB3ZSB3aWxsIHVzZSBERU0gYWx0aXR1ZGUgbWVhc3VyZW1lbnQgZm9yIG91ciBmdXJ0aGVyIGFuYWx5c2lzLiAgCgpOb3cgdGhhdCB3ZSBoYXZlIG9idGFpbmVkIHJlbGlhYmxlIGFsdGl0dWRlIG1lYXN1cmVtZW50cywgd2Ugd2lsbCBleHRyYWN0IGxhbmR1c2UgdmFsdWVzIGZvciB0aGUgcmVjb3JkZWQgdHJhamVjdG9yaWVzLiAKCmBgYHtyfQojIGV4dHJhY3QgbGFuZHVzZSB2YWx1ZXMgb2YgcmVjb3JkZWQgdHJhamVjdG9yaWVzCmxhbmR1c2VUcmFja3MgPC0gZXh0cmFjdChsYW5kVXNlLCBhcy5kYXRhLmZyYW1lKGdyb3Vwc0NsZWFuZWRbLGMoIngiLCJ5IildKSwgbWV0aG9kPSdzaW1wbGUnLCBuYS5ybT1UUlVFLCBkZj1UUlVFKQpsYW5kdXNlVHJhY2tzJGFuaW1hbCA8LSB1bmxpc3QoZ3JvdXBzQ2xlYW5lZFssImlkIl0pCmNvbG5hbWVzKGxhbmR1c2VUcmFja3MpIDwtIGMoIklEIiwgInJhc3RlclZhbCIsICJhbmltYWwiKQpgYGAKCiMjIFNpbXVsYXRpb25zCkluIHRoZSBuZXh0IHNlY3Rpb24gd2Ugd2lsbCBzdGFydCB3aXRoIHRoZSBzaW11bGF0aW9ucyBvZiBhbmltYWwgdHJhamVjdG9yaWVzLiBXZSB3aWxsIHVzZSB0aGUgc2ltbS5jcncgZnVuY3Rpb24gb2YgdGhlIGFkZWhhYml0YXRMVCBwYWNrYWdlIGZvciB0aGUgc2ltdWxhdGlvbnMuIFdlIHdyYXBwZWQgdGhpcyBmdW5jdGlvbiBpbiB0aGUgc2ltdWxhdGVNb3ZlbWVudCBmdW5jdGlvbiBzbyB0aGF0IGl0IGlzIGVhc3kgdG8gc3BlY2lmeSB0aGUgbnVtYmVyIG9mIHNpbXVsYXRpb25zIGFuZCBzYXZlIGFsbCBzaW11bGF0aW9uIGluIGFuIGNvbnZlbmllbnQgZGF0YWZvcm1hdC4gVGhlIHNpbXVsYXRpb25zIHN0YXJ0IGF0IHRoZSBzYW1lIGxvY2F0aW9uIGFzIHRoZSByZXNwZWN0aXZlIGFuaW1hbCwgYW5kIHdpbGwgaGF2ZSB0aGUgc2FtZSBsZW5ndGguCgpgYGB7cn0KIyBudW1iZXIgb2Ygc2ltdWxhdGlvbnMgcGVyIGFuaW1hbApuU2ltdWxhdGlvbnMgPC0gNSAgIAoKIyBwZXJmb3JtIHNpbXVsYXRpb25zCnNpbXVsYXRpb25zIDwtIHNpbXVsYXRlTW92ZW1lbnQodHJhamVjdG9yaWVzID0gbW92ZW1lbnRUcmFqZWN0b3JpZXNDbGVhbmVkLCBuU2ltdWxhdGlvbnMgPSBuU2ltdWxhdGlvbnMsIHByb2o0ID0gcHJvajR6b25lMzIpCmBgYAoKTGV0J3MgdmlzdWFsaXplIHNvbWUgc2ltdWxhdGlvbnMgb24gYW4gaW50ZXJhY3RpdmUgbWFwIQpgYGB7cn0KIyBwbG90IGV4YW1wbGUgb2Ygc2ltdWxhdGVkIHRyYWplY3RvcnkKZXhhbXBsZVNpbTEgPC0gc2ltdWxhdGlvbnNbWzJdXVtbMV1dW1sxXV0KZXhhbXBsZVNpbTIgPC0gc2ltdWxhdGlvbnNbWzJdXVtbMl1dW1sxXV0KCiMgY3JlYXRlIHNwYXRpYWwgbGluZQpzaW1FeGFtcGxlMVdHUzg0IDwtIGNyZWF0ZVNwYXRpYWxMaW5lKGxvY2F0aW9uZGF0YSA9IGV4YW1wbGVTaW0xLCBwcm9qNGRhdGFmcmFtZSA9IHByb2o0em9uZTMyLCBwcm9qNGxpbmUgPSBwcm9qNFdHUzg0LCBsaW5lSWQgPSBhbmltYWwpCnNpbUV4YW1wbGUyV0dTODQgPC0gY3JlYXRlU3BhdGlhbExpbmUobG9jYXRpb25kYXRhID0gZXhhbXBsZVNpbTIsIHByb2o0ZGF0YWZyYW1lID0gcHJvajR6b25lMzIsIHByb2o0bGluZSA9IHByb2o0V0dTODQsIGxpbmVJZCA9IGFuaW1hbCkKCm0gPC0gbGVhZmxldCgpICU+JSAKICBzZXRWaWV3KGxuZz0xMS4wMzY3LCBsYXQ9NDYuMDMzMSwgem9vbSA9IDExKSAlPiUKICAjIGJhc2VsYXllcnMKICBhZGRUaWxlcyhncm91cCA9ICdTdHJlZXQgbWFwJykgJT4lICAKICBhZGRQcm92aWRlclRpbGVzKCdTdGFtZW4uVGVycmFpbicsIGdyb3VwID0gJ1RlcnJhaW4nKSAlPiUgCiAgYWRkUHJvdmlkZXJUaWxlcygnRXNyaS5Xb3JsZEltYWdlcnknLCBncm91cCA9ICdTYXRlbGxpdGUnKSAlPiUKICAjIG92ZXJsYXkgZ3JvdXBzCiAgYWRkUG9seWxpbmVzKGRhdGEgPSBzaW1FeGFtcGxlMVdHUzg0LCB3ZWlnaHQgPSAxLCBvcGFjaXR5ID0gMC44LCBjb2xvciA9ICJvcmFuZ2UiLCBncm91cCA9ICdTaW11bGF0aW9uIDEnKSAlPiUgCiAgYWRkUG9seWxpbmVzKGRhdGEgPSBzaW1FeGFtcGxlMldHUzg0ICwgd2VpZ2h0ID0gMSwgb3BhY2l0eSA9IDAuOCwgY29sb3IgPSAicmVkIiwgZ3JvdXAgPSAnU2ltdWxhdGlvbiAyJykgJT4lIAogIGFkZFBvbHlsaW5lcyhkYXRhID0gdHJhamVjdEFsZXNzYW5kcmEsIHdlaWdodCA9IDEsIG9wYWNpdHkgPSAwLjgsIGNvbG9yID0gImJsdWUiLCBncm91cCA9ICdBbGVzc2FuZHJhJykgJT4lIAogIGFkZExheWVyc0NvbnRyb2woCiAgICBiYXNlR3JvdXBzID0gYygnU3RyZWV0IG1hcCcsICdUZXJyYWluJywgJ1NhdGVsbGl0ZScpLAogICAgb3ZlcmxheUdyb3VwcyA9IGMoJ0FsZXNzYW5kcmEnLCAnU2ltdWxhdGlvbiAxJywgJ1NpbXVsYXRpb24gMicpLAogICAgb3B0aW9ucyA9IGxheWVyc0NvbnRyb2xPcHRpb25zKGNvbGxhcHNlZCA9IEZBTFNFKQogICkKbSAKYGBgCldlIGV4dHJhY3QgdGhlIGFsdGl0dWRlIGFuZCBsYW5kdXNlIHZhbHVlcyBvZiBzaW11bGF0ZWQgdHJhamVjdG9yaWVzIGFuZCBzdG9yZSB0aGVtIGluIGEgbWF0cml4IGluIG9yZGVyIHRvIGNvbXBhcmUgdGhlbSB3aXRoIHRoZSByZWNvcmRlZCBHUFMgdHJhamVjdG9yaWVzIG9mIG91ciBhbmltYWxzLgpgYGB7cn0KIyBleHRyYWN0IGFsdGl0dWRlIGFuZCBsYW5kdXNlIHZhbHVlcyBvZiBzaW11bGF0aW9ucyAKc2ltdWxhdGlvbkVsZXZhdGlvbnMgPC0gZXh0cmFjdFJhc3RlclZhbHVlcyhERU0sIHNpbXVsYXRpb25zKQpzaW11bGF0aW9uTGFuZFVzZSA8LSBleHRyYWN0UmFzdGVyVmFsdWVzKGxhbmRVc2UsIHNpbXVsYXRpb25zKQoKIyBjb21iaW5lIHJlY29yZGVkIGFuZCBzaW11bGF0ZWQgaGVpZ2h0IGRhdGEgaW4gb25lIG1hdHJpeApzaW1FbENvbWJpIDwtIGNvbWJpbmVTaW1UcmFjayhoZWlnaHRERU0sIGFuaW1hbE5hbWVzLCBzaW11bGF0aW9uRWxldmF0aW9ucykKc2ltTGFuZENvbWJpIDwtIGNvbWJpbmVTaW1UcmFjayhsYW5kdXNlVHJhY2tzLCBhbmltYWxOYW1lcywgc2ltdWxhdGlvbkxhbmRVc2UpCmBgYAoKIyMgQ29tcGFyaXNvbiByZWNvcmRlZCBhbmQgc2ltdWxhdGVkIHRyYWplY3RvcmllcwoKIyMjIEVsZXZhdGlvbgpXZSBjYW4gZXhwbG9yZSB3aGV0aGVyIG91ciByb2UgZGVlciBoYXZlIGEgcHJlZmVyZW5jZSBmb3IgYWx0aXR1ZGUgdGhyb3VnaCBhIHZpc3VhbGl6YXRpb24gb2YgbW92ZW1lbnQgb24gYSBERU0uCmBgYHtyfQojIHZhcmlhYmxlcwpjb2xvcnMgPC0gYygicmVkIiwiYmx1ZSIsICJvcmFuZ2UiLCAieWVsbG93IiwgInB1cnBsZSIpCm5hbWVzIDwtIGxpc3QoYygiQWdvc3Rpbm8iLCAiQWxsZXNzYW5kcmEiLCAiRGFpZWxhIiwgIiBEZWNpbW8iLCAiU2FuZHJvIikpCgojIHNlbGVjdCB0aGVtZSB0byBwbG90IHdpdGggcmlnaHQgY29sb3JzCm15VGhlbWU9cmFzdGVyVGhlbWUocmVnaW9uPXJldihicmV3ZXIucGFsKCdZbEduJywgbj05KSkpCgojIGNyZWF0ZSBwbG90IG9mIERFTSB3aXRoIGFkZGVkIHRyYWplY3RvcmllcwpsZXZlbHBsb3QoREVNLCBtYWluID0gIkFsdGl0dWRlIG9mIHJlY29yZGVkIHJvZSBkZWVyIGxvY2F0aW9ucyIsIG1hcmdpbiA9IEZBTFNFLCBwYXIuc2V0dGluZ3M9bXlUaGVtZSwgeGxpbSA9IGMoNjQ3MDAwLCA2NzAwMDApLCBrZXkgPSBsaXN0KHNwYWNlID0gJ2JvdHRvbScsIHBvaW50cyA9IGxpc3QobHR5ID0gMSwgY29sID0gY29sb3JzKSwgdGV4dCA9IG5hbWVzICkpICsgCiAgICBsYXR0aWNlRXh0cmE6OmxheWVyKHsKICB0cmFqZWN0QWdvc3Rpbm9ab25lMzIgPC0gc3BUcmFuc2Zvcm0odHJhamVjdEFnb3N0aW5vLCBDUlMocHJvajR6b25lMzIpKQogIHNwLmxpbmVzKHRyYWplY3RBZ29zdGlub1pvbmUzMiwgY29sID0gJ3JlZCcpfSkgKwogICAgbGF0dGljZUV4dHJhOjpsYXllcih7CiAgdHJhamVjdEFsbGVzc2FuZHJhWm9uZTMyIDwtIHNwVHJhbnNmb3JtKHRyYWplY3RBbGVzc2FuZHJhLCBDUlMocHJvajR6b25lMzIpKQogIHNwLmxpbmVzKHRyYWplY3RBbGxlc3NhbmRyYVpvbmUzMiwgY29sID0gJ2JsdWUnKX0pICsKICAgIGxhdHRpY2VFeHRyYTo6bGF5ZXIoewogIHRyYWplY3REYW5pZWxhWm9uZTMyIDwtIHNwVHJhbnNmb3JtKHRyYWplY3REYW5pZWxhLCBDUlMocHJvajR6b25lMzIpKQogIHNwLmxpbmVzKHRyYWplY3REYW5pZWxhWm9uZTMyLCBjb2wgPSAnb3JhbmdlJyl9KSArCiAgICBsYXR0aWNlRXh0cmE6OmxheWVyKHsKICB0cmFqZWN0RGVjaW1vWm9uZTMyIDwtIHNwVHJhbnNmb3JtKHRyYWplY3REZWNpbW8sIENSUyhwcm9qNHpvbmUzMikpCiAgc3AubGluZXModHJhamVjdERlY2ltb1pvbmUzMiwgY29sID0gJ3llbGxvdycpfSkgKwogICAgbGF0dGljZUV4dHJhOjpsYXllcih7CiAgdHJhamVjdFNhbmRyb1pvbmUzMiA8LSBzcFRyYW5zZm9ybSh0cmFqZWN0U2FuZHJvLCBDUlMocHJvajR6b25lMzIpKQogIHNwLmxpbmVzKHRyYWplY3RTYW5kcm9ab25lMzIsIGNvbCA9ICdwdXJwbGUnKX0pCmBgYAoKUGxvdHMgYWxsb3cgdXMgdG8gY29tcGFyZSB0aGUgcmVjb3JkZWQgYWx0aXR1ZGUgb2Ygb3VyIGFuaW1hbHMgd2l0aCB0aGUgc2ltdWxhdGlvbnMuCmBgYHtyfQojIHBsb3QgdGhlIHByb2ZpbGVzIG9mIHRoZSBzaW11bGF0ZWQgcHJvZmlsZXMgYW5kIHRoZSB0cmFqZWN0b3J5CnBsb3RQcm9maWxlcyhzaW1FbENvbWJpLCBhbmltYWxOYW1lcykKYGBgClRoZSByZWNvcmRlZCB0cmFqZWN0b3JpZXMgc2hvdyBjbGVhcmx5IGxlc3MgdmFyaWF0aW9uIHRoYW4gdGhlIHNpbXVsYXRlZCB0cmFqZWN0b3JpZXMuIFRoaXMgcmVzdWx0IHN1Z2dlc3QgdGhhdCByb2UgZGVlciBsaWtlIHRvIHN0YXkgb24gYSBzaW1pbGFyIGFsdGl0dWRlIGZvciBhIGxvbmdlciB0aW1lcGVyaW9kLiAKCkluIHRoZXNlIGJveHBsb3RzIHdlIGNhbiBjb21wYXJlIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIGVsZXZhdGlvbiBvZiB0aGUgcmVjb3JkZWQgdHJhamVjdG9yaWVzIGFuZCB0aGUgc2ltdWxhdGVkIHRyYWplY3RvcmllcyB0byBjb25maXJtIG91ciB2aXN1YWwgaW50ZXJwcmV0YXRpb24gb2YgdGhlIHBsb3R0ZWQgcHJvZmlsZXMuIApgYGB7cn0KIyB2YXJpYWJsZXMgZm9yIGJveHBsb3QgCnhsYWIgPC0gIlRyYWplY3RvcnkiCnlsYWIgPC0gIkVsZXZhdGlvbiAobSkiCnRpdGxlIDwtICJDb21wYXJpc29uIG9mIHJlY29yZGVkIGFuZCBzaW11bGF0ZWQgR1BTIHRyYWplY3RvcmllcyBvZiIKCiMgdmlzdWFsaXplIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gcmVjb3JkZWQgYW5kIHNpbXVsYXRlZCBkYXRhIGluIGJveHBsb3RzCmJveHBsb3RsaXN0IDwtIGJveHBsb3RQcm9maWxlcyhzaW1FbENvbWJpLCBhbmltYWxOYW1lcywgeGxhYiwgeWxhYiwgdGl0bGUsIGFkZE5hbWUgPSBUUlVFKSAKCiMgYXJyYWdlIGJveHBsb3RzCmdyaWQuYXJyYW5nZShib3hwbG90bGlzdFtbMV1dLGJveHBsb3RsaXN0W1syXV0sYm94cGxvdGxpc3RbWzNdXSxib3hwbG90bGlzdFtbNF1dLGJveHBsb3RsaXN0W1s1XV0sIGxheW91dF9tYXRyaXggPSByYmluZChjKDEsMiksIGMoMyw0KSxjKDUsNikpKQpgYGAKV2UgY2FuIGFsc28gY29tcGFyZSB0aGUgc3VtbWFyeSBzdGF0aXN0aWNzIChtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24pIG9mIHRoZSByZWNvcmRlZCBhbmQgc2ltdWxhdGVkIHRyYWplY3Rvcmllcy4gCmBgYHtyfQojIGNhbGN1bGF0ZSBzdW1tYXJ5IHN0YXRpc3RpY3MgZm9yIHRoZSByZWNvcmRlZCBhbmQgc2ltdWxhdGVkIHRyYWplY3RvcmllcwpzdW1tYXJ5U3RhdHMgPC0gc3VtU3RhdHMoc2ltRWxDb21iaSwgYW5pbWFsTmFtZXMpCgojIGNyZWF0ZSBlbXB0eSB2ZWN0b3JzCnhBeFNpbSA8LSBhcy5pbnRlZ2VyKCkKbWVhbnNSZWMgPC0gYXMubnVtZXJpYygpCm1lYW5zU2ltIDwtIGFzLm51bWVyaWMoKQpzZFJlYyA8LSBhcy5udW1lcmljKCkKc2RTaW0gPC0gYXMubnVtZXJpYygpCgojIHN0b3JlIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MgaW4gYSB2ZWN0b3IgZm9yIHBsb3R0aW5nCmZvciAoYW5pbWFsIGluIDE6bGVuZ3RoKGFuaW1hbE5hbWVzKSl7CiAgbWVhbnNSZWMgPC0gYyhtZWFuc1JlYywgc3VtbWFyeVN0YXRzW1thbmltYWxdXVsxLDFdKQogIG1lYW5zU2ltIDwtIGMobWVhbnNTaW0sIHN1bW1hcnlTdGF0c1tbYW5pbWFsXV1bMSwyOm5jb2woc3VtbWFyeVN0YXRzW1thbmltYWxdXSldKQogIHNkUmVjIDwtIGMoc2RSZWMsIHN1bW1hcnlTdGF0c1tbYW5pbWFsXV1bMywxXSkKICBzZFNpbSA8LSBjKHNkU2ltLCBzdW1tYXJ5U3RhdHNbW2FuaW1hbF1dWzMsMjpuY29sKHN1bW1hcnlTdGF0c1tbYW5pbWFsXV0pXSkKICAKICAjIGNyZWF0ZSBhbiBpbmRleCB2ZWN0b3IgZm9yIHRoZSB4LWF4aXMKICBmb3IgKGNvbCBpbiAxOmxlbmd0aCgyOm5jb2woc3VtbWFyeVN0YXRzW1thbmltYWxdXSkpKXsKICAgIHhBeFNpbSA8LSBjKHhBeFNpbSwgYW5pbWFsKQogIH0KfQoKIyBwbG90CnBhcihtZnJvdz1jKDEsMiksIHhwZCA9IFRSVUUpCnBsb3QoeEF4U2ltLCBtZWFuc1NpbSwgY29sID0gYygnZ3JleScpLCB5bGltID0gYyg0MDAsMTYwMCksIG1haW4gPSAnTWVhbiBlbGV2YXRpb24nLCB4bGFiID0gJ2FuaW1hbCBudW1iZXInLCB5bGFiID0gJ2VsZXZhdGlvbiAobSknLCBwY2ggPSAxOSkKcG9pbnRzKG1lYW5zUmVjLCBjb2wgPSAncmVkJywgcGNoID0gMTkpCnBsb3QoeEF4U2ltLCBzZFNpbSwgY29sID0gYygnZ3JleScpLCB5bGltID0gYygxMDAsNjUwKSwgbWFpbiA9ICdTdGFuZGFyZCBkZXZpYXRpb24gZWxldmF0aW9uJywgeGxhYiA9ICdhbmltYWwgbnVtYmVyJywgeWxhYiA9ICdlbGV2YXRpb24gKG0pJywgcGNoID0gMTkpCnBvaW50cyhzZFJlYywgY29sID0gJ3JlZCcsIHBjaCA9IDE5KQpsZWdlbmQoLTAuOCwwLCBjKCJSZWNvcmRlZCIsICJTaW11bGF0ZWQiKSwgY29sID0gYygicmVkIiwgImdyZXkiKSwgcGNoID0gMTksIGJ0eSA9ICduJykKcGFyKG1mcm93PWMoMSwxKSwgeHBkID0gRkFMU0UpCgpgYGAKVGhlc2UgdmFyaW91cyByZXN1bHRzIGFsbCBzaG93YSBzaW1pbGFyIHRyZW5kOyByb2UgZGVlciBzdGljayB0byBhIHJlbGF0aXZlbHkgc2ltaWxhciBhbHRpdHVkZXMgY29tcGFyZWQgdG8gdGhlIHNpbXVsYXRlZCB0cmFqZWN0b3JpZXMuIEFzIHdlbGwgdGhleSBzZWVtIHRvIHByZWZlciBoaWdoZXIgYWx0aXR1ZGUgb3ZlciBsb3dlciBhbHRpdHVkZS4gSG93ZXZlciwgdGhpcyBjYW4gYmUgdGhlIHJlc3VsdCBmcm9tIGh1bWFuIHByZWZlcmVuY2UgZm9yIGxvd2VyIGFsdGl0dWRlcy4uLiAgCgojIyMgTGFuZHVzZQpUaGUgbmV4dCBzZWN0aW9uIGFuYWx5c2VzIHdoZXRoZXIgdGhlIHJvZSBkZWVyIGhhdmUgYSBwcmVmZXJlbmNlIGZvciBjZXJ0YWluIGxhbmQgdXNlIHR5cGVzLiBQbGVhc2Ugbm90ZSB0aGF0IHRoZSBmb2xsb3dpbmcgcGxvdCBoYXMgZG91YmxlIGxhYmVscyBhbmQgYSBzdWItb3B0aW1hbCB2aXN1YWxpemF0aW9uLiBTYWRseSwgd2UgZGlkIG5vdCBoYXZlIGVub3VnaCB0aW1lIHRvIGZpZ3VyZSB0aGVzZSBpc3N1ZXMgb3V0LiBXZSBob3BlIHlvdSB3aWxsIGZvcmdpdmUgdXMgdGhlc2UgZmxhd3MhIApgYGB7cn0KIyB2YXJpYWJsZXMKY29sb3JzQW5pbWFscyA8LSBjKCJyZWQiLCJibHVlIiwgIm9yYW5nZSIsICJ5ZWxsb3ciLCAicHVycGxlIikKY29sb3JzTGFuZFVzZSA8LSBjKCd3aGl0ZScsJ2F6dXJlMycsICdhenVyZTMnLCAnYXp1cmU0JywnYXp1cmU0JywnYmlzcXVlNCcsJ2Jpc3F1ZTQnLCdjaGFydHJldXNlJywgJ2NoYXJ0cmV1c2UyJywnY2hhcnRyZXVzZTInLCdjaGFydHJldXNlMycsJ2RhcmtvbGl2ZWdyZWVuMScsICdkYXJrb2xpdmVncmVlbjEnLCdkYXJrb2xpdmVncmVlbicsJ2RhcmtvbGl2ZWdyZWVuJywnZGFya29yYW5nZTInLCdkYXJrb3JhbmdlMicsJ2Rhcmtnb2xkZW5yb2QzJywnZGFya2N5YW4nLCAnZGFya3NsYXRlZ3JheTEnKQpuYW1lcyA8LSBsaXN0KGMoIkFnb3N0aW5vIiwgIkFsbGVzc2FuZHJhIiwgIkRhaWVsYSIsICIgRGVjaW1vIiwgIlNhbmRybyIpKQoKIyBjb3B5IGxhbmR1c2UKbGFuZFVzZVRlc3QgPC0gbGFuZFVzZSAKCiMgc3RhcnQgZm9yIHJlY2xhc3NpZmljYXRpb24gdGFibGUKZnJvbSA8LSAxCnRvIDwtIGFzLmludGVnZXIoKQpzdGFydCA8LSAxCmNsYXMgPC0gYXMuaW50ZWdlcigpCgojIG1ha2UgcmVjbGFzc2lmaWNhdGlvbiB0YWJsZSB0byByZW1vdmUgZG91YmxlIGxhYmxlcwpmb3IgKGxhYmVsIGluIDE6KGxlbmd0aChsYW5kVXNlTGVnZW5kJExBQkVMMiktMSkpewogIAogIHRoaXNvbmUgPC0gbGFuZFVzZUxlZ2VuZCRMQUJFTDJbbGFiZWxdCiAgbmV4dG9uZSA8LSBsYW5kVXNlTGVnZW5kJExBQkVMMltsYWJlbCsxXQogIAogICMgY2hlY2sgaWYgbGFiZWwgaXMgc2FtZSBhcyBuZXh0IG9uZQogIGlmICghdGhpc29uZSA9PSBuZXh0b25lKXsKICAgIHRvIDwtIGModG8sbGFiZWwpCiAgICBmcm9tIDwtIGMoZnJvbSwgbGFiZWwrMSkKICB9CiAgCn0KIyBhZGQgbGFzdCBudW1iZXIgdG8gZ2V0IHNhbWUgbGVuZ3RoCnRvIDwtIGModG8sbGVuZ3RoKGxhbmRVc2VMZWdlbmQkTEFCRUwyKSkKIyBjcmVhdGUgdGhlIHJlY2xhc3NpZmljYXRpbiB0YWJsZQpyY2wgPC0gY2JpbmQoZnJvbSwgdG8sIHRvKQoKIyByZWNsYXNzaWZ5CmxhbmRVc2VUZXN0IDwtIHJlY2xhc3NpZnkobGFuZFVzZVRlc3QsIHJjbCkKCiMgcmF0aWZ5IHRvIGdldCBsYWJlbHMKbGFuZFVzZVRlc3QgPC0gcmF0aWZ5KGxhbmRVc2VUZXN0KQpyYXQgPC0gbGV2ZWxzKGxhbmRVc2VUZXN0KVtbMV1dCnJhdDIgPC0gbGVmdF9qb2luKHJhdCwgbGFuZFVzZUxlZ2VuZCwgYnkgPSBjKCJJRCIgPSAiR1JJRF9DT0RFIikpCnJhdDJkcm9wIDwtIHJhdDJbLGMoIklEIiwiTEFCRUwyIildCmxldmVscyhsYW5kVXNlVGVzdCkgPC0gcmF0MmRyb3AKCiMgcGxvdApsZXZlbHBsb3QobGFuZFVzZVRlc3QsIGNvbC5yZWdpb25zPSBjb2xvcnNMYW5kVXNlLCBvcGFjaXR5ID0gMC4zLCBtYWluID0gIkxhbmR1c2Ugb2YgcmVjb3JkZWQgcm9lIGRlZXIgbG9jYXRpb25zIiwgbWFyZ2luID0gRkFMU0UsIHBhci5zZXR0aW5ncz1teVRoZW1lLCB4bGltID0gYyg2NDcwMDAsIDY3MDAwMCksIGtleSA9IGxpc3Qoc3BhY2UgPSAnYm90dG9tJywgcG9pbnRzID0gbGlzdChsdHkgPSAxLCBjb2wgPSBjb2xvcnNBbmltYWxzKSwgdGV4dCA9IG5hbWVzICkpICsgCiAgICBsYXR0aWNlRXh0cmE6OmxheWVyKHsKICB0cmFqZWN0QWdvc3Rpbm9ab25lMzIgPC0gc3BUcmFuc2Zvcm0odHJhamVjdEFnb3N0aW5vLCBDUlMocHJvajR6b25lMzIpKQogIHNwLmxpbmVzKHRyYWplY3RBZ29zdGlub1pvbmUzMiwgY29sID0gJ3JlZCcpfSkgKwogICAgbGF0dGljZUV4dHJhOjpsYXllcih7CiAgdHJhamVjdEFsbGVzc2FuZHJhWm9uZTMyIDwtIHNwVHJhbnNmb3JtKHRyYWplY3RBbGVzc2FuZHJhLCBDUlMocHJvajR6b25lMzIpKQogIHNwLmxpbmVzKHRyYWplY3RBbGxlc3NhbmRyYVpvbmUzMiwgY29sID0gJ2JsdWUnKX0pICsKICAgIGxhdHRpY2VFeHRyYTo6bGF5ZXIoewogIHRyYWplY3REYW5pZWxhWm9uZTMyIDwtIHNwVHJhbnNmb3JtKHRyYWplY3REYW5pZWxhLCBDUlMocHJvajR6b25lMzIpKQogIHNwLmxpbmVzKHRyYWplY3REYW5pZWxhWm9uZTMyLCBjb2wgPSAnb3JhbmdlJyl9KSArCiAgICBsYXR0aWNlRXh0cmE6OmxheWVyKHsKICB0cmFqZWN0RGVjaW1vWm9uZTMyIDwtIHNwVHJhbnNmb3JtKHRyYWplY3REZWNpbW8sIENSUyhwcm9qNHpvbmUzMikpCiAgc3AubGluZXModHJhamVjdERlY2ltb1pvbmUzMiwgY29sID0gJ3llbGxvdycpfSkgKwogICAgbGF0dGljZUV4dHJhOjpsYXllcih7CiAgdHJhamVjdFNhbmRyb1pvbmUzMiA8LSBzcFRyYW5zZm9ybSh0cmFqZWN0U2FuZHJvLCBDUlMocHJvajR6b25lMzIpKQogIHNwLmxpbmVzKHRyYWplY3RTYW5kcm9ab25lMzIsIGNvbCA9ICdwdXJwbGUnKX0pCmBgYApUaGUgYWJvdmUgbWFwIGRvZXMgbm90IGdpdmUgdXMgYSB2ZXJ5IGNsZWFyIGltcHJlc3Npb24gYXMgdG8gd2hldGhlciBvdXIgYW5pbWFscyBwcmVmZXIgY2VydGFpbiB0eXBlcyBvZiBsYW5kdXNlLiBIb3dldmVyLCBpdCBkb2VzIGNsZWFybHkgc2hvdyB0aGF0IHRoZSBob21lcmFuZ2Ugb2Ygb3VyIGFuaW1hbHMgbW9zdGx5IGNvbnNpc3RzIG9mIGZvcmVzdCBhbmQgcGFzdHVyZS4gCgpCYXJwbG90cyBtYXkgcHJvdmlkZSBhIGNsZWFyZXIgaW5kaWNhdGlvbiBhcyB0byB3aGV0aGVyIG91ciBhbmltYWxzIGhhdmUgYSBwcmVmZXJlbmNlIGZvciBwYXJ0aWN1bGFyIHR5cGVzIG9mIGxhbmR1c2U6CmBgYHtyfQojIGFkZCBsZWdlbmQgdG8gbGFuZCB1c2UgbWF0cml4IGZvciByZWNvcmRlZCBhbmQgc2ltdWxhdGVkIGRhdGEKc2ltTGFuZENvbWJpREZMZWdlbmQgPC0gYWRkTGVnZW5kKHNpbUxhbmRDb21iaSwgbGVnZW5kID0gbGFuZFVzZUxlZ2VuZCwgYW5pbWFsTmFtZXMgPSBhbmltYWxOYW1lcykKCiMgbG9vcCBvdmVyIHRoZSBtYXRyaWNlcyBmb3IgdGhlIGRpZmZlcmVudCBhbmltYWxzCmZvciAoYW5pbWFsIGluIDE6bGVuZ3RoKGFuaW1hbE5hbWVzKSl7CiAKICAjIGdyb3VwIGJhc2VkIG9uIGluZCAocmVjb3JkZWQgLyBudW1iZXIgb2Ygc2ltdWxhdGlvbnMpCiAgZ3JvdXBlZExhbmRVc2VBbmltYWwgPC0gYXMuZGF0YS5mcmFtZShzaW1MYW5kQ29tYmlERkxlZ2VuZFtbYW5pbWFsXV0pCiAgZ3JvdXBlZExhbmRVc2VDb3VudCA8LSBncm91cGVkTGFuZFVzZUFuaW1hbCAlPiUgZ3JvdXBfYnkoaW5kLCBMQUJFTDIpICU+JSBzdW1tYXJpc2UoY291bnQgPSBuKCkpCiAgCiAgIyBjcmVhdGUgaGlzdG9ncmFtCiAgYXNzaWduKHBhc3RlMCgiaCIsYW5pbWFsKSxnZ3Bsb3QoZGF0YT1ncm91cGVkTGFuZFVzZUNvdW50LCBhZXMoeD1MQUJFTDIsIHk9Y291bnQsIGZpbGw9aW5kKSkgKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSgpKSArIGdndGl0bGUocGFzdGUoIkxhbmQgdXNlIG9mIiwgYW5pbWFsTmFtZXNbYW5pbWFsXSkpICsgeGxhYihOVUxMKSArIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMTEsIGhqdXN0ID0gMSkpKQp9CgpncmlkLmFycmFuZ2UoaDEsaDIsIGxheW91dF9tYXRyaXggPSByYmluZChjKDEsMSksYygyLDIpKSkKZ3JpZC5hcnJhbmdlKGgzLGg0LCBsYXlvdXRfbWF0cml4ID0gcmJpbmQoYygxLDEpLGMoMiwyKSkpCmdyaWQuYXJyYW5nZShoNSwgbGF5b3V0X21hdHJpeCA9IHJiaW5kKGMoMSwxKSxjKDIsMikpKQoKYGBgClRoZXNlIHBsb3RzIGNvbmZpcm0gdGhhdCBvdXIgYW5pbWFscyBtb3N0bHkgcmVzaWRlIGluIGZvcmVzdCBhbmQgcGFzdHVyZSBhcmVhcy4gT3VyIHNpbXVsYXRlZCB0cmFqZWN0b3JpZXMgcHJvdmlkZSBzaW1pbGFyIHJlc3VsdHMgdG8gdGhlIHJlY29yZGVkIG1vdmVtZW50LCB3aGljaCBtYXkgZXhwbGFpbmVkIGJ5IHRoZSBmYWN0IHRoYXQgdGhlc2UgbGFuZHVzZSBjbGFzc2VzIGFyZSBwcmV2YWxlbnQgaW4gdGhlIGFyZWEgaW4gd2hpY2ggb3VyIGFuaW1hbHMgbGl2ZS4gVGhlIGZhY3QgdGhhdCB0aGlzIGlzIHRoZWlyIHByZWZlcnJlZCBob21lIHJhbmdlIGRvZXMgc3VnZ2VzdCB0aGF0IG91ciByb2UgZGVlciBsb3ZlIHRoZWlyIHN0cm9sbHMgdGhyb3VnaCBmb3Jlc3QgYW5kIHBhc3R1cmUhCgojIyBDb25jbHVzaW9uClRoaXMgcHJvamVjdCBoYXMgY29tcGFyZWQgcmVjb3JkZWQgYW5kIHNpbXVsYXRlZCByb2UgZGVlciBtb3ZlbWVudCBpbiB0aGUgYXJlYSBvZiBUcmVudG8sIEl0YWx5LiBJdCBoYXMgYW5hbHlzZWQgdG8gd2hhdCBleHRlbnQgZWxldmF0aW9uIGFuZCBsYW5kdXNlIGNhbiBleHBsYWluIHJvZSBkZWVyIG1vdmVtZW50IGluIHRoZSBhcmVhLiBUaGUgcmVzdWx0cyBvZiB0aGUgYW5hbHlzaXMgc3VnZ2VzdCB0aGF0IHRoZSByb2UgZGVlciBzdGljayB0byBhIHJlbGF0aXZlbHkgc21hbGwgaG9tZSByYW5nZSBhbmQgc3RhYmxlIGFsdGl0dWRlIGNvbXBhcmVkIHRvIHRoZSBzaW11bGF0ZWQgbG9jYXRpb25zLiBSb2UgZGVlciBoYWQgYSBwcmVmZXJlbmNlIGZvciBmb3Jlc3QgYW5kIHBhc3R1cmUuIEhvd2V2ZXIsIHRoZSBkaWZmZXJlbmNlIHdpdGggc2ltdWxhdGVkIGRhdGEgaXMgc21hbGwsIGR1ZSB0byB0aGUgaGlnaCBwcmV2YWxlbmNlIG9mIHRoZXNlIGxhbmQgdXNlIHR5cGVzIGluIHRoZSBob21lIHJhbmdlIG9mIHRoZSByb2UgZGVlci4KCmBgYHtyfQojIGRpc2Nvbm5lY3QgZGF0YWJhc2UKZGJEaXNjb25uZWN0KG1vdmVtZW50REIpCmBgYAoKIyMgUmVmZXJlbmNlcwpVcmJhbm8sIEYuLCAmIENhZ25hY2NpLCBGLiAoMjAxNCkuIFNwYXRpYWwgZGF0YWJhc2UgZm9yIEdQUyB3aWxkbGlmZSB0cmFja2luZyBkYXRhLiBTcHJpbmdlciBJbnRlcm5hdGlvbmFsIFB1Ymxpc2hpbmcu